I've always used the following rule for signatures of functions that return ref-counted objects based on whether they do an AddRef or not, but want to explain it to my colleagues too... So my question is, is the rule described below a widely followed rule? I'm looking for pointers to (for example) coding rules that advocate this style.
If the function does not add a reference to the object, it should be returned as the return value of the function:
class MyClass
{
protected:
IUnknown *getObj() { return m_obj; }
private:
IUnknown *m_obj;
};
However, if the function adds a reference to the object, then a pointer-to-pointer of the object is passed as a parameter to the function:
class MyClass
{
public:
void getObj(IUnknown **outObj) { *outObj = m_obj; (*outObj)->AddRef(); }
private:
IUnknown *m_obj;
};
It's much more typical to use the reference-counting smart pointers for cases when a new object is created and the caller has to take ownership of it.
I've used this same style on projects with a lot of COM. It was taught to me by a couple of people that learned it when they worked at NuMega on a little thing called SoftICE. I think this is also the style taught in the book "Essential COM", by Don Box (here it is at Amazon). At one point in time this book was considered the Bible for COM. I think the only reason this isn't still the case is that COM has become so much more than just COM.
All that said, I prefer CComPtr and other smart pointers.
One approach is to never use the function's return value. Only use output parameters, as in your second case. This is already a rule anyway in published COM interfaces.
Here's an "official" reference but, as is typical, it doesn't even mention your first case: http://support.microsoft.com/kb/104138
But inside a component, banning return values makes for ugly code. It is much nicer to have composability - i.e. putting functions together conveniently, passing the return value of one function directly as an argument to another.
Smart pointers allow you to do that. They are banned in public COM interfaces but then so are non-HRESULT return values. Consequently, your problem goes away. If you want to use a return value to pass back an interface pointer, do it via a smart pointer. And store members in smart pointers as well.
However, suppose for some reason you didn't want to use smart pointers (you're crazy, by the way!) then I can tell you that your reasoning is correct. Your function is acting as a "property getter", and in your first example it should not AddRef.
So your rule is correct (although there's a bug in your implementation which I'll come to in a second, as you may not have spotted it.)
This function wants an object:
void Foo(IUnknown *obj);
It doesn't need to affect obj's refcount at all, unless it wants to store it in a member variable. It certainly should NOT be the responsibility of Foo to call Release on obj before it returns! Imagine the mess that would create.
Now this function returns an object:
IUnknown *Bar();
And very often we like to compose functions, passing the output of one directly to another:
Foo(Bar());
This would not work if Bar had bumped up the refcount of whatever it returned. Who's going to Release it? So Bar does not call AddRef. This means that it is returning something that it stores and manages, i.e. it's effectively a property getter.
Also if the caller is using a smart pointer, p:
p = Bar();
Any sane smart pointer is going to AddRef when it is assigned an object. If Bar had also AddRef-ed well, we have again leaked one count. This is really just a special case of the same composability problem.
Output parameters (pointer-to-pointer) are different, because they aren't affected by the composability problem in the same way:
Again, smart pointers provide the most common case, using your second example:
myClass.getObj(&p);
The smart pointer isn't going to do any ref-counting here, so getObj has to do it.
Now we come to the bug. Suppose smart pointer p already points to something when you pass it to getObj...
The corrected version is:
void getObj(IUnknown **outObj)
{
if (*outObj != 0)
(*outObj)->Release();
*outObj = m_obj;
(*outObj)->AddRef(); // might want to check for 0 here also
}
In practise, people make that mistake so often that I find it simpler to make my smart pointer assert if operator& is called when it already has an object.
Related
I have a class containing large member variables. In my case, the large member variable is a container of many objects and it must be private as I don't want to allow a user to modify it directly
class Example {
public:
std::vector<BigObject> get_very_big_object() const { return very_big_object; }
private:
std::vector<BigObject> very_big_object;
}
I want a user to be able to view the object without making a copy:
Example e();
auto very_big_object = e.get_very_big_object(); // Uh oh, made a copy
cout << very_big_object[11]; // Look at any element in the vector etc
I'm a bit confused about the best way to do it. I thought about returning a constant reference, i.e., make my getter:
const std::vector<BigObject>& get_very_big_object() const { return very_big_object; }
I read this article that suggests it could be risky and that that a smart pointer std::unique_ptr could be better, but that this problem can be best solved using modern C++11 move semantics. But I found that a bit cryptic.
What's the modern best practice for doing this?
I read this article that suggests it could be risky and that that a smart pointer std::unique_ptr could be better, but that this problem can be best solved using modern C++11 move semantics.
On this point, the article is flat-out wrong. A smart pointer does not remove the "risk".
Quick summary of relevant parts of the article
If a class returns a const reference to a data member, client code may introduce a const_cast and thereby change the data member without going through the class' API.
The article proposes (incorrectly) that the above can be avoided by using a smart pointer. The setup is for the class to maintain a shared pointer to the data, and have the getter return that pointer cast to a shared pointer to const data.
Critique of the points
First of all, this does not work. All one has to do is de-reference the smart pointer to get a const reference to the data, which can then be const_cast as before. Using the author's own example, instead of
std::string &evil = const_cast<std::string&>(obj.someStr());
use
std::string &evil = const_cast<std::string&>(*obj.str_ptr());
to get the same data-changing results when returning a smart pointer. The entire article is not wrong, but it does get several points wrong. This is one of them.
Second of all, this is not your concern. When you return a const reference, you are telling client code that this value is not to be changed. If the client code does so anyway, it's the client code that broke the agreement. Essentially, the client code invoked undefined behavior, so your class is free to do anything, even crash the program.
What's the modern best practice for doing this?
Simply return a const reference. (Most rules have exceptions, but in my experience, this one seems to be on target 95-99.9% of the time.)
What I did when I was working on my BDD-library for school is to create a wrapper class called VeryBigObject, which contacts the singleton upon instantiation and hides a reference-counting pointer, from there you can override the operator->() method to allow for direct access to the class's methods.
So something like this
class VeryBigObject {
private:
vector<BigObject>* obj;
public:
VeryBigObject() {
// find a way to instantiate with a pointer, not by copying
}
VeryBigObject(const VeryBigObject& o) {
// Update reference counts
obj = o.obj;
}
virtual VeryBigObject operator->(const VeryBigObject&); // I don't remember how to do this one, just google it.
... // Do other overloads as you see fit to mask working with the pointer directly.
};
This allows you to create a small portable class that you don't have to worry about copying, but also has access to the larger object easily. You'll still need to worry about things like caching and such though
I am writing code that utilizes COM interfaces. I am basing my code on examples that I have found online. I do not want to utilize smart pointers in this case because I want to understand the basics of COM and not just have a smart pointer class do all of the work for me.
In order to frame my questions, let's assume I have a class similar to the following:
public class TestClass
{
private:
IUnknown *m_pUnknown;
public:
TestClass();
void AssignValue();
}
TestClass::TestClass()
{
m_pUnknown = NULL;
}
void TestClass::AssignValue()
{
IUnknown *pUnknown = NULL;
//Assign value to pUnknown here - not relevant to my questions
m_pUnknown = pUnknown;
pUnknown->Release();
}
Now on to my specific questions.
1) The examples I've seen to not use AddRef() when initializing a value, such as in the class constructor. Does the AddRef() happen "automatically" behind the scenes when a COM pointer is first assigned a value?
2) Although my code example does not show it, it is my understanding that in the AssignValue() method, when you assign a second value to overwrite the value of pUnknown (originally set in the class constructor), Release() is automatically called. After assigning the new value to pUnknown its reference count stands at zero. I need to call pUnknown->AddRef() immediately after the reassignment. Is my understanding correct?
Notes: I assume we are ignoring exceptions for simplicity here. If this was for real, you would want to use smart pointers to help keep things straight in the presence of exceptions. Similarly, I am not worrying about proper copying or destruction of instances of your example class or multi-threading. (Your raw pointers cannot be used from different threads as simply as you might assume.)
First, You need to make any necessary calls to COM. The only way anything might happen "automatically" behind the scenes would be if you were using smart pointers to do them.
1) The examples you refer to have to be getting their COM interface pointers from somewhere. This would be by making COM calls, e.g., CoCreateInstance() and QueryInterface(). These calls are passed the address of your raw pointer and set that raw pointer to the appropriate value. If they weren't also implicitly AddRef'ed, the reference count might be 0 and COM could delete the associated COM object before your program could do anything about it. So such COM calls must include an implicit AddRef() on your behalf. You are responsible for a Release() to match this implicit AddRef() that you instigated with one of these other calls.
2a) Raw pointers are raw pointers. Their value is garbage until you arrange for them to be set to something valid. In particular, assigning a value to one will NOT auto-magically call a function. Assigning to a raw pointer to an interface does not call Release() - you need to do that at the appropriate time. In your post, it appears that you are "overwriting" a raw pointer that had previously been set to NULL, hence there was no existing COM interface instance in the picture. There could not have been an AddRef() on something that doesn't exist, and must not be a Release() on something that isn't there.
2b)
Some of the code you indicated by a comment in your example is very relevant, but can easily be inferred. You have a local raw pointer variable, pUnknown. In the absent code, you presumably use a COM call that obtains an interface pointer, implicitly AddRefs it, and fills in your raw pointer with the proper value to use it. This gives you the responsibility for one corresponding Release() when you are done with it.
Next, you set a member raw pointer variable (m_pUnknown) with this same value. Depending on the previous use of this member variable, you might have needed to call Release() with its former value before doing this.
You now have 2 raw pointers set to the value to work with this COM interface instance and responsibility for one Release() due to 1 implicit AddRef() call. There are two ways to deal with this, but neither is quite what you have in your sample.
The first, most straightforward, and proper approach (which others have correctly pointed out & I skipped passed in the first version of this answer) is one AddRef() and one Release() per pointer. Your code is missing this for m_pUnknown. This requires adding m_pUnknown->AddRef() immediately after the assignment to m_pUnknown and 1 corresponding call to Release() "someplace else" when you are done using the current interface pointer from m_pUnknown. One usual candidate for this "someplace else" in your code is in the class destructor.
The second approach is more efficient, but less obvious. Even if you decide not to use it, you may see it, so should at least be aware of it. Following the first approach you would have the code sequence:
m_pUnknown = pUnknown;
m_pUnknown->AddRef();
pUnknown->Release();
Since pUnknown and m_pUnknown are set the same here, the Release() is immediately undoing the AddRef(). In this circumstance, eliding this AddRef/Release pair is reference count neutral and saves 2 round trips into COM. My mental model for this is a transfer of the interface and reference count from one pointer to the other. (With smart pointers it would look like newPtr.Attach( oldPtr.Detach() ); ) This approach leaves you with the original/not shown implicit AddRef() and needing to add the same m_pUnknown->Release() "someplace else" as in the first alternative.
In either approach, you exactly match AddRefs (implicit or explicit) with Releases for each interface and never go to a 0 reference count until you are done with the interface. Once you do hit 0, you do not attempt to use the value in the pointer.
Avi Berger already posted a great answer, but here is the same thing stated another way in case it helps with understanding.
In COM, reference counting is done within the COM object. The COM runtime will destruct and free an object whose reference count reaches 0. (This might be delayed by some time from the point of the count hitting 0).
Everything else is a convention. The usual convention amongst C++ COM programmers is that raw interface pointers should be treated as owning pointers. This concept means that any time a pointer points to a COM object, the pointer owns that object.
Using this terminology, the object may have multiple owners at any one time, and the object will be destroyed when nobody owns it.
However, raw pointers in C++ don't have ownership semantics built in. So you have to implement it yourself by making function calls:
Call AddRef on an interface pointer when that pointer takes ownership of an object. (You'll need to be aware of which Windows API functions or other library functions already do this, to avoid you doing it twice)
Call Release on an interface pointer when that pointer is about to stop owning an object.
The benefit of smart pointers is that they make it impossible for you to forget to call Release when an interface pointer stops owning an object. This includes the following cases:
Pointer goes out of scope.
Pointer is made to stop pointing to the object, by using assignment operator.
So, looking at your sample code. You have the pointer m_pUnknown. You want this pointer to take ownership of the object, so the code should be:
m_pUnknown = pUnknown;
m_pUnknown->AddRef();
You will also need to add code to your class destructor and your class assignment operator to call m_pUnknown->Release(). I would very strongly recommend wrapping these calls in the smallest class possible (that is, write your own smart pointer and make TestClass have that smart pointer as a member variable). Assuming of course you don't want to use an existing COM smart pointer class for pedagogical reasons.
The call pUnknown->Release(); is correct because pUnknown currently owns the object, and the pointer is about to stop owning the object due to the fact that it will be destroyed when the function block ends.
You may observe that it would be possible to remove both of the lines m_pUnknown->AddRef() and pUnknown->Release(). The code will behave exactly the same. However , it is better to follow the convention outlined above. Sticking to a convention helps yourself to avoid errors and it also helps other coders to understand your code.
To put it another way, the usual convention is to think of the pointer as having a reference count of either 0 or 1, even though the reference counting is not actually implemented that way.
First, my apologies. My attempt to simplify my code for the sake of clarity turned out to be misguided. However, I believe my questions were answered. If I may, I will summarize.
1) Any COM object that is assigned a value other than NULL needs to be immediately followed by AddRef() unless the AddRef() was implicitly handled (as is the case with some Windows API calls).
2) Any reassignment of value to a COM pointer, assuming that the "before" value is not NULL must be immediately proceeded by Release(). AddRef() would then by needed as mentioned in #1.
3) Any COM variable whose value needs to be preserved beyond its current scope requires that it have a reference count of at least 1 upon exiting its said scope. This may mean that an AddRef() is required.
Would this be a fair summary? Did I miss anything?
I recently came across some C++ code that looked like this:
class SomeObject
{
private:
// NOT a pointer
BigObject foobar;
public:
BigObject * getFoobar() const
{
return &foobar;
}
};
I asked the programmer why he didn't just make foobar a pointer, and he said that this way he didn't have to worry about allocating/deallocating memory. I asked if he considered using some smart pointer, he said this worked just as well.
Is this bad practice? It seems very hackish.
That's perfectly reasonable, and not "hackish" in any way; although it might be considered better to return a reference to indicate that the object definitely exists. A pointer might be null, and might lead some to think that they should delete it after use.
The object has to exist somewhere, and existing as a member of an object is usually as good as existing anywhere else. Adding an extra level of indirection by dynamically allocating it separately from the object that owns it makes the code less efficient, and adds the burden of making sure it's correctly deallocated.
Of course, the member function can't be const if it returns a non-const reference or pointer to a member. That's another advantage of making it a member: a const qualifier on SomeObject applies to its members too, but doesn't apply to any objects it merely has a pointer to.
The only danger is that the object might be destroyed while someone still has a pointer or reference to it; but that danger is still present however you manage it. Smart pointers can help here, if the object lifetimes are too complex to manage otherwise.
You are returning a pointer to a member variable not a reference. This is bad design.
Your class manages the lifetime of foobar object and by returning a pointer to its members you enable the consumers of your class to keep using the pointer beyond the lifetime of SomeObject object. And also it enables the users to change the state of SomeObject object as they wish.
Instead you should refactor your class to include the operations that would be done on the foobar in SomeObject class as methods.
ps. Consider naming your classes properly. When you define it is a class. When you instantiate, then you have an object of that class.
It's generally considered less than ideal to return pointers to internal data at all; it prevents the class from managing access to its own data. But if you want to do that anyway I see no great problem here; it simplifies the management of memory.
Is this bad practice? It seems very hackish.
It is. If the class goes out of scope before the pointer does, the member variable will no longer exist, yet a pointer to it still exists. Any attempt to dereference that pointer post class destruction will result in undefined behaviour - this could result in a crash, or it could result in hard to find bugs where arbitrary memory is read and treated as a BigObject.
if he considered using some smart pointer
Using smart pointers, specifically std::shared_ptr<T> or the boost version, would technically work here and avoid the potential crash (if you allocate via the shared pointer constructor) - however, it also confuses who owns that pointer - the class, or the caller? Furthermore, I'm not sure you can just add a pointer to an object to a smart pointer.
Both of these two points deal with the technical issue of getting a pointer out of a class, but the real question should be "why?" as in "why are you returning a pointer from a class?" There are cases where this is the only way, but more often than not you don't need to return a pointer. For example, suppose that variable needs to be passed to a C API which takes a pointer to that type. In this case, you would probably be better encapsulating that C call in the class.
As long as the caller knows that the pointer returned from getFoobar() becomes invalid when the SomeObject object destructs, it's fine. Such provisos and caveats are common in older C++ programs and frameworks.
Even current libraries have to do this for historical reasons. e.g. std::string::c_str, which returns a pointer to an internal buffer in the string, which becomes unusable when the string destructs.
Of course, that is difficult to ensure in a large or complex program. In modern C++ the preferred approach is to give everything simple "value semantics" as far as possible, so that every object's life time is controlled by the code that uses it in a trivial way. So there are no naked pointers, no explicit new or delete calls scattered around your code, etc., and so no need to require programmers to manually ensure they are following the rules.
(And then you can resort to smart pointers in cases where you are totally unable to avoid shared responsibility for object lifetimes.)
Two unrelated issues here:
1) How would you like your instance of SomeObject to manage the instance of BigObject that it needs? If each instance of SomeObject needs its own BigObject, then a BigObject data member is totally reasonable. There are situations where you'd want to do something different, but unless that situation arises stick with the simple solution.
2) Do you want to give users of SomeObject direct access to its BigObject? By default the answer here would be "no", on the basis of good encapsulation. But if you do want to, then that doesn't change the assessment of (1). Also if you do want to, you don't necessarily need to do so via a pointer -- it could be via a reference or even a public data member.
A third possible issue might arise that does change the assessment of (1):
3) Do you want to give users of SomeObject direct access to an instance of BigObject that they continue using beyond the lifetime of the instance of SomeObject that they got it from? If so then of course a data member is no good. The proper solution might be shared_ptr, or for SomeObject::getFooBar to be a factory that returns a different BigObject each time it's called.
In summary:
Other than the fact it doesn't compile (getFooBar() needs to return const BigObject*), there is no reason so far to suppose that this code is wrong. Other issues could arise that make it wrong.
It might be better style to return const & rather than const *. Which you return has no bearing on whether foobar should be a BigObject data member.
There is certainly no "just" about making foobar a pointer or a smart pointer -- either one would necessitate extra code to create an instance of BigObject to point to.
I came accross several questions where answers state that using T* is never the best idea.
While I already make much use of RIIC, there is one particular point in my code, where I use T*. Reading about several auto-pointers, I couldn't find one where I'd say that I have a clear advantage from using it.
My scenario:
class MyClass
{
...
// This map is huge and only used by MyClass and
// and several objects that are only used by MyClass as well.
HashMap<string, Id> _hugeIdMap;
...
void doSomething()
{
MyMapper mapper;
// Here is what I pass. The reason I can't pass a const-ref is
// that the mapper may possibly assign new IDs for keys not yet in the map.
mapper.setIdMap(&_hugeIdMap);
mapper.map(...);
}
}
MyMapper now has a HashMap<...>* member, which - according to highly voted answers in questions on unrelated problems - never is a good idea (Altough the mapper will go out of scope before the instance of MyClass does and hence I do not consider it too much of a problem. There's no new in the mapper and no delete will be needed).
So what is the best alternative in this particular use-case?
Personally I think a raw pointer (or reference) is okay here. Smart pointers are concerned with managing the lifetime of the object pointed to, and in this case MyMapper isn't managing the lifetime of that object, MyClass is. You also shouldn't have a smart pointer pointing to an object that was not dynamically allocated (which the hash map isn't in this case).
Personally, I'd use something like the following:
class MyMapper
{
public:
MyMapper(HashMap<string, Id> &map)
: _map(map)
{
}
private:
HashMap<string, Id> &_map
};
Note that this will prevent MyMapper from having an assignment operator, and it can only work if it's acceptable to pass the HashMap in the constructor; if that is a problem, I'd make the member a pointer (though I'd still pass the argument as a reference, and do _map(&map) in the initializer list).
If it's possible for MyMapper or any other class using the hash map to outlive MyClass, then you'd have to start thinking about smart pointers. In that case, I would probably recommend std::shared_ptr, but you'd have to use it everywhere: _hugeIdMap would have to be a shared_ptr to a dynamically allocated value, not a regular non-pointer field.
Update:
Since you said that using a reference is not acceptable due to the project's coding standards, I would suggest just sticking with a raw pointer for the reasons mentioned above.
Naked pointers (normally referred to as raw pointers) are just fine when the object has no responsibility to delete the object. In the case of MyMapper then the pointer points to an object already owned by MyClass and is therefore absolutely fine to not delete it. The problem arises when you use raw pointers when you do intend for objects to be deleted through them, which is where problems lie. People only ask questions when they have problems, which is why you almost always see it only used in a problematic context, but raw pointers in a non-owning context is fine.
How about passing it into the constructor and keeping a reference (or const-reference) to it? That way your intent of not owning the object is made clear.
Passing auto-pointers or shared-pointers are mostly for communicating ownership.
shared pointers indicate it's shared
auto-pointers indicate it's the receivers responsibility
references indicate it's the senders responsibility
blank pointers indicate nothing.
About your coding style:
our coding standards have a convention that says never pass non-const references.
Whether you use the C++ reference mechanism or the C++ pointer mechanism, you're passing a (English-meaning) reference to the internal storage that will change. I think your coding standard is trying to tell you not to do that at all, not so much that you can't use references to do so but that you can do it in another way.
I've been evaluating various smart pointer implementations (wow, there are a LOT out there) and it seems to me that most of them can be categorized into two broad classifications:
1) This category uses inheritance on the objects referenced so that they have reference counts and usually up() and down() (or their equivalents) implemented. IE, to use the smart pointer, the objects you're pointing at must inherit from some class the ref implementation provides.
2) This category uses a secondary object to hold the reference counts. For example, instead of pointing the smart pointer right at an object, it actually points at this meta data object... Who has a reference count and up() and down() implementations (and who usually provides a mechanism for the pointer to get at the actual object being pointed to, so that the smart pointer can properly implement operator ->()).
Now, 1 has the downside that it forces all of the objects you'd like to reference count to inherit from a common ancestor, and this means that you cannot use this to reference count objects that you don't have control over the source code to.
2 has the problem that since the count is stored in another object, if you ever have a situation that a pointer to an existing reference counted object is being converted into a reference, you probably have a bug (I.E., since the count is not in the actual object, there is no way for the new reference to get the count... ref to ref copy construction or assignment is fine, because they can share the count object, but if you ever have to convert from a pointer, you're totally hosed)...
Now, as I understand it, boost::shared_pointer uses mechanism 2, or something like it... That said, I can't quite make up my mind which is worse! I have only ever used mechanism 1, in production code... Does anyone have experience with both styles? Or perhaps there is another way thats better than both of these?
"What is the best way to implement smart pointers in C++"
Don't! Use an existing, well tested smart pointer, such as boost::shared_ptr or std::tr1::shared_ptr (std::unique_ptr and std::shared_ptr with C++ 11)
If you have to, then remember to:
use safe-bool idiom
provide an operator->
provide the strong exception guarantee
document the exception requirements your class makes on the deleter
use copy-modify-swap where possible to implement the strong exception guarantee
document whether you handle multithreading correctly
write extensive unit tests
implement conversion-to-base in such a way that it will delete on the derived pointer type (policied smart pointers / dynamic deleter smart pointers)
support getting access to raw pointer
consider cost/benifit of providing weak pointers to break cycles
provide appropriate casting operators for your smart pointers
make your constructor templated to handle constructing base pointer from derived.
And don't forget anything I may have forgotten in the above incomplete list.
Just to supply a different view to the ubiquitous Boost answer (even though it is the right answer for many uses), take a look at Loki's implementation of smart pointers. For a discourse on the design philosophy, the original creator of Loki wrote the book Modern C++ Design.
I've been using boost::shared_ptr for several years now and while you are right about the downside (no assignment via pointer possible), I think it was definitely worth it because of the huge amount of pointer-related bugs it saved me from.
In my homebrew game engine I've replaced normal pointers with shared_ptr as much as possible. The performance hit this causes is actually not so bad if you are calling most functions by reference so that the compiler does not have to create too many temporary shared_ptr instances.
Boost also has an intrusive pointer (like solution 1), that doesn't require inheriting from anything. It does require changing the pointer to class to store the reference count and provide appropriate member functions. I've used this in cases where memory efficiency was important, and didn't want the overhead of another object for each shared pointer used.
Example:
class Event {
public:
typedef boost::intrusive_ptr<Event> Ptr;
void addRef();
unsigned release();
\\ ...
private:
unsigned fRefCount;
};
inline void Event::addRef()
{
fRefCount++;
}
inline unsigned Event::release(){
fRefCount--;
return fRefCount;
}
inline void intrusive_ptr_add_ref(Event* e)
{
e->addRef();
}
inline void intrusive_ptr_release(Event* e)
{
if (e->release() == 0)
delete e;
}
The Ptr typedef is used so that I can easily switcth between boost::shared_ptr<> and boost::intrusive_ptr<> without changing any client code
If you stick with the ones that are in the standard library you will be fine.
Though there are a few other types than the ones you specified.
Shared: Where the ownership is shared between multiple objects
Owned: Where one object owns the object but transfer is allowed.
Unmovable: Where one object owns the object and it can not be transferred.
The standard library has:
std::auto_ptr
Boost has a couple more than have been adapted by tr1 (next version of the standard)
std::tr1::shared_ptr
std::tr1::weak_ptr
And those still in boost (which in relatively is a must have anyway) that hopefully make it into tr2.
boost::scoped_ptr
boost::scoped_array
boost::shared_array
boost::intrusive_ptr
See:
Smart Pointers: Or who owns you baby?
It seems to me this question is kind of like asking "Which is the best sort algorithm?" There is no one answer, it depends on your circumstances.
For my own purposes, I'm using your type 1. I don't have access to the TR1 library. I do have complete control over all the classes I need to have shared pointers to. The additional memory and time efficiency of type 1 might be pretty slight, but memory usage and speed are big issues for my code, so type 1 was a slam dunk.
On the other hand, for anyone who can use TR1, I'd think the type 2 std::tr1::shared_ptr class would be a sensible default choice, to be used whenever there isn't some pressing reason not to use it.
The problem with 2 can be worked around. Boost offers boost::shared_from_this for this same reason. In practice, it's not a big problem.
But the reason they went with your option #2 is that it can be used in all cases. Relying on inheritance isn't always an option, and then you're left with a smart pointer you can't use for half your code.
I'd have to say #2 is best, simply because it can be used in any circumstances.
Our project uses smart pointers extensively. In the beginning there was uncertainty about which pointer to use, and so one of the main authors chose an intrusive pointer in his module and the other a non-intrusive version.
In general, the differences between the two pointer types were not significant. The only exception being that early versions of our non-intrusive pointer implicitly converted from a raw pointer and this can easily lead to memory problems if the pointers are used incorrectly:
void doSomething (NIPtr<int> const &);
void foo () {
NIPtr<int> i = new int;
int & j = *i;
doSomething (&j); // Ooops - owned by two pointers! :(
}
A while ago, some refactoring resulted in some parts of the code being merged, and so a choice had to be made about which pointer type to use. The non-intrusive pointer now had the converting constructor declared as explicit and so it was decided to go with the intrusive pointer to save on the amount of code change that was required.
To our great surprise one thing we did notice was that we had an immediate performance improvement by using the intrusive pointer. We did not put much research into this, and just assumed that the difference was the cost of maintaining the count object. It is possible that other implementations of non-intrusive shared pointer have solved this problem by now.
What you are talking about are intrusive and non-intrusive smart pointers. Boost has both. boost::intrusive_ptr calls a function to decrease and increase the reference count of your object, everytime it needs to change the reference count. It's not calling member functions, but free functions. So it allows managing objects without the need to change the definition of their types. And as you say, boost::shared_ptr is non-intrusive, your category 2.
I have an answer explaining intrusive_ptr: Making shared_ptr not use delete. In short, you use it if you have an object that has already reference counting, or need (as you explain) an object that is already referenced to be owned by an intrusive_ptr.