I'm currently trying to find out how to properly use the shared_ptr feature of C++11 in C++ APIs. The main area where I need it is in container classes (Like nodes in a scene graph for example which may contain a list of child nodes and a reference to the parent node and stuff like that). Creating copies of the nodes is not an option and using references or pointers is pain in the ass because no one really knows who is responsible for destructing the nodes (And when someone destructs a node which is still referenced by some other node the program will crash).
So I think using shared_ptr may be a good idea here. Let's take a look at the following simplified example (Which demonstrates a child node which must be connected to a parent node):
#include <memory>
#include <iostream>
using namespace std;
class Parent {};
class Child {
private:
shared_ptr<Parent> parent;
public:
Child(const shared_ptr<Parent>& parent) : parent(parent) {}
Parent& getParent() { return *parent.get(); }
};
int main() {
// Create parent
shared_ptr<Parent> parent(new Parent());
// Create child for the parent
Child child(parent);
// Some other code may need to get the parent from the child again like this:
Parent& p = child.getParent();
...
return 0;
}
This API forces the user to use a shared_ptr for creating the actual connection between the child and the parent. But in other methods I want a more simple API, that's why the getParent() method returns a reference to the parent and not the shared_ptr.
My first question is: Is this a correct usage of shared_ptr? Or is there room for improvement?
My second question is: How do I properly react on null-pointers? Because the getParent method returns a reference the user may think it never can return NULL. But that's wrong because it will return NULL when someone passes a shared pointer containing a null-pointer to the constructor. Actually I don't want null pointers. The parent must always be set. How do I properly handle this? By manually checking the shared pointer in the constructor and throwing an exception when it contains NULL? Or is there a better way? Maybe some sort of non-nullable-shared-pointer?
Using shared pointers for the purpose you describe is reasonable and increasingly common in C++11 libraries.
A few points to note:
On an API, taking a shared_ptr as an argument forces the caller construct a shared_ptr. This is definitely a good move where there is a transfer of ownership of the pointee. In cases where the function merely uses a shared_ptr, it may be acceptable to take a reference to the object or the shared_ptr
You are using shared_ptr<Parent> to hold a back reference to the parent object whilst using one in the other direction. This will create a retain-cycle resulting in objects that never get deleted. In general, used a shared_ptr when referencing from the top down, and a weak_ptr when referencing up. Watch out in particular for delegate/callback/observer objects - these almost always want a weak_ptr to the callee. You also need to take care around lambdas if they are executing asynchronously. A common pattern is to capture a weak_ptr.
Passing shared pointers by reference rather than value is a stylistic point with arguments for and against. Clearly when passing by reference you are not passing ownership (e.g. increasing the reference count on the object). On the other hand, you are also not taking the overhead either. There is a danger that you under reference objects this way. On a more practical level, with a C++11 compiler and standard library, passing by value should result in a move rather than copy construction and be very nearly free anyway. However, passing by reference makes debugging considerably easier as you won't be repeatedly stepping into shared_ptr's constructor.
Construct your shared_ptr with std::make_shared rather than new() and shared_ptr's constructor
shared_ptr<Parent> parent = std::make_shared<Parent>();
With modern compilers and libraries this can save a call to new().
both shared_ptr and weak_ptr can contain NULL - just as any other pointer can. You should always get in the habit of checking before dereferencing and probably assert()ing liberally too. For the constructor case, you can always accept NULL pointers and instead throw at the point of use.
You might consider using a typedef for your shared pointer type. One style that is sometimes used is follows:
typedef std::weak_ptr<Parent> Parent_P;
typedef std::shared_ptr<Parent> Parent_WkP;
typedef std::weak_ptr<Child> Child_P;
typedef std::shared_ptr<Child> Child_WkP;
It's also useful to know that in header files you can forward declare shared_ptr<Type> without having seen a full declaration for Type. This can save a lot of header bloat
The way that you are using shared pointers is correct with 2 caveats.
That your tree of parents and childen must share the lifetime of the pointers with other objects. If your Parent child tree will be the sole users of the pointer, please use a unique_ptr. If another object controls the lifetime of the pointer are you only want to reference the pointer, you may be better off using a weak_ptr unless the lifetime is guaranteed to exceed your Parent Child tree the raw pointer may be suitable.. Please remember that with shared_ptr you can get circular reference so it is not a silver bullet.
As for how to control NULL pointers: well this all comes down to the contract implicit in your API. If the user is not allowed to supply a null pointer, you just need to document this fact. The best way to do this is to include an assert that the pointer is not null. This will crash your application in debug mode (if the pointer is null) but will not incur a runtime penalty on your release binary. If however a null pointer is is an allowed input for some reason, then you need to provide correct error handling in the case of a null pointer.
Children do not own their parents. Rather, it's the other way around. If children need to be able to get their parents, then use a non-owning pointer or reference. Use shared (or better, unique if you can) pointer for parent to child.
Related
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?
Edit
I suppose the code below would assume I have an overloaded version of addChild() that accepts a Sprite already wrapped in a unique_ptr, where taking ownership would be fine. Just thought I'd mention that before someone else did. :) . I made up all the code here after a very long day, so please take it as pseudo code quality meant only to demonstrate the issue at hand.
Original Question
I'm writing a framework where there is a display list, parents/children etc. I'm thinking that using unique_ptr<Sprite> for example is the way to go here, since when you add a child to a parent display object, it's only logical that the parent now becomes the sole owner of that child.
However, there will be methods available such as getChildAt(index) and getChildByName, etc, which I believe should return a reference or pointer value, since these methods are simply meant to expose a child to operations, not transfer ownership.
Finally, the issue and the reason for this question, is in the following situation. Lets assume we have two Sprite objects which are children of the root of display list, Stage. Let's say we have a third child Sprite.
Stage newStage;
std::unique_ptr<Sprite> parentOne(new Sprite);
std::unique_ptr<Sprite> parentTwo(new Sprite);
newStage.addChild(parentOne); //Stage takes ownership of parentOne
newStage.addChild(parentTwo); //Stage takes ownership of parentTwo
std::unique_ptr<Sprite> someChild(new Sprite);
parentOne->addChild(someChild) //parentOne takes ownership of someChild.
Now, somewhere else lets say in the code base of the game or whatever using this framework, someChild is accessed via getChildAt(int index);.
Sprite& child = parentOne->getChildAt(0);
It would be perfectly legal for the following to then happen.
parentTwo->addChild(child);
The addChild method handles removing the child from it's previous parent, if a parent exists, so that the new parent can now make this child part of its section of the display list.
I'm returning the child(ren) from each sprite as a reference or pointer, because we don't want to hand off ownership (in methods such as getChildAt()), just provide access to the child. We don't want to hand it off as a unique_ptr and have it fall out of scope and die.
However, as I say, it would be perfectly legal and normal for this child (now accessed by a reference or pointer) to be passed off to another container (lets say in a drag and drop operation, dragging an item from one list to another). The problem we have now is that the unique ownership needs to be transferred from one parent to another, but we only have a reference or raw pointer.
I'm wondering what a sane solution to this problem would be. If I return a pointer, is it possible to transfer the ownership correctly at this stage?
void Sprite::addChild(Sprite* newChildToOwn)
{
/* by checking newChildToOwn->parent we can see that the child is already owned
by someone else. We need to not only remove the child from that parents' part of the
display list and add it here, but transfer exclusive object ownership of newChildToOwn
to this->.
*/
}
The release method gets you the pointer to the object and releases it from the unique_ptr
http://en.cppreference.com/w/cpp/memory/unique_ptr/release
For your structure, you should probably have method called releaseChild(index) that handles you the ownership by returning pointer.
To transfer ownership you need to have access to the unique_ptr as the raw pointer knows nothing of how it is being used.
Would it work to have the remove child method return the unique_ptr so that the object is kept alive during the transfer and the Sprite will be able to take the ownership? This will allow references to be used in other places as you have already.
I'm woring against a model which consists of a number of different types (Properties, Parent, Child, etc). Each type is associated with a set of functions from a c api. For example:
Type "Properties":
char* getName(PropertiesHandle);
char* getDescription(PropertiesHandle);
Type "Parent"
PropertiesHandle getProperties(ParentHandle);
ChildHanlde getFirstChild(ParentHandle);
Type "Child"
PropertiesHandle getProperties(ChildHandle);
ParentHanlde getParent(ChildHandle);
ChildHandle getNextChild(ChildHandle);
I have in turn created a set of C++ interfaces for this c api library, as follows:
class IProperties
{
public:
virtual std::string getName() = 0;
virtual std::string getDescription() = 0;
};
class IParent
{
public:
virtual std::shared_ptr<IProperties> getProperties() = 0;
virtual std::shared_ptr<IChild> getFirstChild() = 0;
};
class IChild
{
public:
virtual std::shared_ptr<IProperties> getProperties() = 0;
virtual std::shared_ptr<IParent> getParent() = 0;
virtual std::shared_ptr<IChild> getNextChild() = 0;
};
I then implement these interfaces via the classes Properties, Parent and Child.
So a Child instance will take its specific ChildHandle via its constructor and its getParent function will look something like this:
std::shared_ptr<IParent> getParent()
{
// get the parent handle and wrap it in a Parent object
return std::shared_ptr<IParent>(new Parent(_c_api->getParent(_handle)));
}
Is it reasonable for me to return a shared_ptr here in your opinion. I cant use std::unique_ptr since Google Mock requires parameters and return values of mocked methods to be copyable. I'm mocking these interfaces in my tests via Google Mock.
I'm thinking also about how things might get optimized in the future which might present the possibly of circular references. This could be caused if caching is used to avoid multiple calls to the C api (for example, no need for a child to establish its parent more than once) combined with say the Child constructor taking its Parent. This would then require the use of weak_ptrs which would change the interfaces and a lot of my code...
The key question is: what are the semantics of the returned pointer?
if the returned parent/child/properties object has a lifetime independent of the returning (presumably, in some sense, owning) object, it's reasonable to return shared_ptr: this indicates that the caller and callee have equal rights to decide the object's lifetime
std::shared_ptr<IChild> child = parent->getFirstChild();
// now I can keep child around ... if parent is destroyed, one
// orphaned subtree is magically kept around. Is this desirable?
if the returned object has a lifetime dependent on the callee's own lifetime, then:
shared_ptr will wrongly suggest it's meaningful for the caller to extend the returned object's lifetime beyond that of the callee
unique_ptr will wrongly suggest transfer of ownership
raw pointer doesn't explicitly make any misleading promises, but doesn't give any hint about correct use either
So, if the caller is just getting a working reference to your object's internal state, without either transfer of ownership or extension of object lifetime, it doesn't suggest using any smart pointer.
Consider just returning a reference.
There's nothing wrong with returning a shared_ptr, but I'll try to convince you that this might not be the best option.
By using a smart pointer you gain the advantage of safety, but the users of your API lose the flexibility of using the type of smart pointer that best fits their needs and instead have to always use shared_ptr.
It also depends on how much you value safety over flexibility, but I would personally consider returning a naked pointer and allow the user to use the smart pointer he wants. Of course, if it is necessary that I use shared_ptr for some reason, I will.
shared_ptr is fine, but it does provide some limitation to the end user, such as C++11 support. A raw pointer, or a trait that allows them to tailor the smart pointer, may provide more flexibility to the end user.
Regardless of the pointer, I suggest being careful with the semantics introduced by the implementation. With the current implementation, with a new wrapped being instantiated for every accessor call, equivalence checks will fail. Consider the following code:
auto child = parent->getFirstChild();
if ( parent == child->getParent() ) // Will be false, as they point to different
// instantiations of Parent.
...
if ( child->getParent() == child->getParent() ) // False for the same reason.
...
auto sibling = child->getNextChild();
if ( parent == sibling->getParent() ) // Also false for the same reason.
...
Also, when using std::shared_ptr, it can be worthwhile to consider using std::make_shared to reduce some of the overhead that occurs with the allocations.
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 have a pointer to a QScriptEngine that I'm passing through the overloaded class constructor of class Evaluator and assigns it to QScriptEngine *engine_ (class Property subclasses Evaluator, and calls this constructor of Evaluator, passing it an already allocated QScriptEngine). The constructor with no arguments creates the new QScriptEngine pointer (class Generic subclasses Evaluator in this way). In the destructor I test if engine_ is not NULL, delete the pointer, then assign it NULL. Should the pointer (engine_) in the derived Property now also be NULL? Something tells me this is not the case. If not, how do you deal with this situation? I need the QScriptEngine to be the same instance throughout. QScriptEngine's = operator is private, or I would be avoiding the pointer all together.
I saw some info on shared pointers (boost::shared_ptr and std:tr1::shared_ptr) in another SO question. I'm already using boost for the regex library, so boost is not out of the question if that's the best way to deal with this. Hopefully there's a non-boost way, for general C++ knowledge and future projects.
You can solve this by giving one of the classes (class A) lifetime control of that pointer, along with a 'getter' method. The other class (class B) would always call A's getter whenever it needed the pointer. That way, A remains in control of the pointer at all times. Downside is the getter function (it will probably inline, but it's still a second indirection). Also, B is going to have to check that pointer for NULL on pretty much every use.
Your other choice is to wrap the pointer in something like boost::shared_ptr which takes care of the problem (if used properly) by holding the underlying pointer, and only deleting it when all objects that share that pointer are deleted. You could write this yourself, but since you already have boost in play, I'd just use their implementation.
A third choice is to re-factor the whole thing so that you don't need a shared pointer. I'd personally never design a C++ program that needed shared pointers, just because it's a spot where memory management bugs could easily creep in over the years, but that's just me.