473,386 Members | 1,673 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Smart pointers and inclomplete types

I have a problem with a cyclic dependency of two classes:
class Iref_count // Interface for the intrusive_ptr
{ friend class int_ptr_base; // for access to Count
private:
volatile unsigned Count;
protected:
Iref_count() : Count(0) {}
// You must not call the non-virtual destructor directly.
~Iref_count() {}
};
class Slice;
class Iterator
{ intrusive_ptr<Sliceroot;
// some more stuff
};
class Slice : public Iref_count
{ scopec_ptr<Iteratorstart;
scopec_ptr<Iteratorstop;
// some more stuff
};
To get this to compile either scoped_ptr or intrusive_ptr have to accept
an incomplete type.

Unfortunately I did not have luck with this so far. Neither Slice nor
Iterator are PODs. And the forward declaration of Slice generates wrong
code in intrusive_ptr at the conversion from Iref_count* to Slice*. The
pointer value is not translated by the offset of Iref_count.

Note that intrusive_ptr is not boost::intrusive_ptr, because that won't
compile on my platform. I wrote something similar (see below). However,
I am unsure whether boost::intrusive_ptr would have defined behavior in
this case, and if it does so, why?
Any Ideas?
The cyclic dependency is really needed from the designs point of view.
/* Abstract non-template base class of int_ptr */
class int_ptr_base
{protected:
Iref_Count* Ptr;
public:
// Store a new object under reference count control
// or initialize a NULL pointer.
int_ptr_base(Iref_Count* ptr);
// Copy constructor
int_ptr_base(const int_ptr_base& r);
// Destructor core
Iref_Count* unassign();
// some more functions...
};

template <class T>
class int_ptr : protected int_ptr_base
{public:
// Store a new object under reference count control
// or initialize a NULL pointer.
int_ptr(T* ptr = NULL) : int_ptr_base(ptr) {}
// Destructor, frees the stored object if this is the last reference.
~int_ptr() { delete (T*)unassign(); }

// Basic operators
T* get() const { return (T*)Ptr; }
T& operator*() const { assert(Ptr); return *(T*)Ptr; }
T* operator->() const { assert(Ptr); return (T*)Ptr; }
// some more functions...
};

int_ptr_base::int_ptr_base(Iref_Count* ptr)
: Ptr(ptr)
{ if (Ptr)
++Ptr->Count; // normally InterlockedInc(Ptr->Count);
}
int_ptr_base::int_ptr_base(const int_ptr_base& r)
: Ptr(r.Ptr)
{ if (Ptr)
++Ptr->Count; // normally InterlockedInc(Ptr->Count);
}

Iref_Count* int_ptr_base::unassign()
{ return Ptr && --Ptr->Count == 0 ? Ptr : NULL; // normally
InterlockedDec(Ptr->Count)
}
Jun 27 '08 #1
2 2364
Marcel Müller wrote:
I have a problem with a cyclic dependency of two classes:
class Iref_count // Interface for the intrusive_ptr
{ friend class int_ptr_base; // for access to Count
private:
volatile unsigned Count;
protected:
Iref_count() : Count(0) {}
// You must not call the non-virtual destructor directly.
~Iref_count() {}
};
class Slice;
class Iterator
{ intrusive_ptr<Sliceroot;
// some more stuff
};
class Slice : public Iref_count
{ scopec_ptr<Iteratorstart;
scopec_ptr<Iteratorstop;
// some more stuff
};
To get this to compile either scoped_ptr or intrusive_ptr have to accept
an incomplete type.

Unfortunately I did not have luck with this so far. Neither Slice nor
Iterator are PODs. And the forward declaration of Slice generates wrong
code in intrusive_ptr at the conversion from Iref_count* to Slice*. The
pointer value is not translated by the offset of Iref_count.

Note that intrusive_ptr is not boost::intrusive_ptr, because that won't
compile on my platform. I wrote something similar (see below). However,
I am unsure whether boost::intrusive_ptr would have defined behavior in
this case, and if it does so, why?
It would not.

However, std::tr1::shared_ptr (and boost::shared_ptr) probably would.
>

Any Ideas?
The cyclic dependency is really needed from the designs point of view.
You might want to have a look at the implementation of boost::shared_ptr.
The key idea is to store a deleter within the shared_ptr and initialize
that one upon construction (with an appropriate default). This way, the
problem can be postponed until shared_ptr objects need to be initialized.
Only at that point, the type has to be complete.

/* Abstract non-template base class of int_ptr */
class int_ptr_base
{protected:
Iref_Count* Ptr;
public:
// Store a new object under reference count control
// or initialize a NULL pointer.
int_ptr_base(Iref_Count* ptr);
// Copy constructor
int_ptr_base(const int_ptr_base& r);
// Destructor core
Iref_Count* unassign();
// some more functions...
};

template <class T>
class int_ptr : protected int_ptr_base
{public:
// Store a new object under reference count control
// or initialize a NULL pointer.
int_ptr(T* ptr = NULL) : int_ptr_base(ptr) {}
// Destructor, frees the stored object if this is the last reference.
~int_ptr() { delete (T*)unassign(); }
The line above is either wrong or too smart: nothing (except the comment)
indicates that the reference has to be last.

// Basic operators
T* get() const { return (T*)Ptr; }
T& operator*() const { assert(Ptr); return *(T*)Ptr; }
T* operator->() const { assert(Ptr); return (T*)Ptr; }
// some more functions...
};

int_ptr_base::int_ptr_base(Iref_Count* ptr)
: Ptr(ptr)
{ if (Ptr)
++Ptr->Count; // normally InterlockedInc(Ptr->Count);
}
int_ptr_base::int_ptr_base(const int_ptr_base& r)
: Ptr(r.Ptr)
{ if (Ptr)
++Ptr->Count; // normally InterlockedInc(Ptr->Count);
}

Iref_Count* int_ptr_base::unassign()
{ return Ptr && --Ptr->Count == 0 ? Ptr : NULL; // normally
InterlockedDec(Ptr->Count)
}

Best

Kai-Uwe Bux
Jun 27 '08 #2
Kai-Uwe Bux wrote:
>Note that intrusive_ptr is not boost::intrusive_ptr, because that won't
compile on my platform. I wrote something similar (see below). However,
I am unsure whether boost::intrusive_ptr would have defined behavior in
this case, and if it does so, why?

It would not.

However, std::tr1::shared_ptr (and boost::shared_ptr) probably would.
>>
Any Ideas?
The cyclic dependency is really needed from the designs point of view.

You might want to have a look at the implementation of boost::shared_ptr.
The key idea is to store a deleter within the shared_ptr and initialize
that one upon construction (with an appropriate default). This way, the
problem can be postponed until shared_ptr objects need to be initialized.
Only at that point, the type has to be complete.
Hmm, I intensionally preferred intrusive pointers because of their small
memory footprint. Furthermore it is a major design change, because the
current interfaces rely on the fact that passing T* instead of
int_ptr<Tas function argument is sufficient even if int_ptr<T>
instances may be assigned from the parameter in the function body.

Maybe I can apply something like that what you have mentioned to the
scoped_ptr and forward declare the Iterator class.

>/* Abstract non-template base class of int_ptr */
class int_ptr_base
{protected:
Iref_Count* Ptr;
public:
// Store a new object under reference count control
// or initialize a NULL pointer.
int_ptr_base(Iref_Count* ptr);
// Copy constructor
int_ptr_base(const int_ptr_base& r);
// Destructor core
Iref_Count* unassign();
// some more functions...
};

template <class T>
class int_ptr : protected int_ptr_base
{public:
// Store a new object under reference count control
// or initialize a NULL pointer.
int_ptr(T* ptr = NULL) : int_ptr_base(ptr) {}
// Destructor, frees the stored object if this is the last reference.
~int_ptr() { delete (T*)unassign(); }

The line above is either wrong or too smart: nothing (except the comment)
indicates that the reference has to be last.
unassign returns NULL unless it removes the last reference. Well, not
documented that nicely. The whole trick is to do anything but the
absolutely needed part in a non-template base. This keeps the binary
compact.
Marcel
Jun 27 '08 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: Bolin | last post by:
Hi all, A question about smart pointers of constant objects. The problem is to convert from Ptr<T> to Ptr<const T>. I have look up and seen some answers to this question, but I guess I am too...
4
by: Eric | last post by:
See question in main function below...TIA. struct A {}; struct B: public A {}; #include <boost/shared_ptr.hpp> #include <set> typedef boost::shared_ptr<A> AP; typedef std::set<AP> AS;
11
by: lokb | last post by:
Hi, I have a structure which and defined a smart pointer to the structure. /* Structure of Begin Document Index Record */ typedef struct BDI_Struct{ unsigned char rname; unsigned short int...
9
by: christopher diggins | last post by:
I would like to survey how widespread the usage of smart pointers in C++ code is today. Any anecdotal experience about the frequency of usage of smart pointer for dynamic allocation in your own...
8
by: Axter | last post by:
I normally use a program call Doxygen to document my source code.(http://www.stack.nl/~dimitri/doxygen) This method works great for small and medium size projects, and you can get good...
33
by: Ney André de Mello Zunino | last post by:
Hello. I have written a simple reference-counting smart pointer class template called RefCountPtr<T>. It works in conjunction with another class, ReferenceCountable, which is responsible for the...
10
by: =?iso-8859-1?q?Ernesto_Basc=F3n?= | last post by:
I am implementing my custom smart pointer: template <typename T> class MySmartPtr { public: MySmartPtr(T* aPointer) { mPointer = aPointer; }
54
by: Boris | last post by:
I had a 3 hours meeting today with some fellow programmers that are partly not convinced about using smart pointers in C++. Their main concern is a possible performance impact. I've been explaining...
50
by: Juha Nieminen | last post by:
I asked a long time ago in this group how to make a smart pointer which works with incomplete types. I got this answer (only relevant parts included): ...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.