Been trying to understand shared pointer for a few days now and it feels like I cant seem to get it. Not sure if it's just to obvious or if it's too complicated. First of all, could anyone please give me an example where you would ACTUALLY use shared pointers. The examples on Wikipedia makes no sense to me. And how would you pass a shared pointer to another function or create an object with a shared pointer. So, how do you pass it around and where would you use it? ANY information or examples would be great.
Also, I have this issue where I don't know what to use. I have this function where I allocate a QFile and passes it to a function in another class. That function takes the file as a QIODevice* and then creates an object containing the file. I was wondering what the best solution would be here and how (if I should) use a shared pointer here? How can I make a shared pointer with <QFile> and pass it in where the function takes <QIODevice>. Feels like I don't get shared pointers at all...
My other approach would be to put the allocation of the QFile in a QScopedPointer. I then pass it to the class and when creating the object where the file will be stored, I use QPointer or QScopedPointer. In the end of the first calling function I should call take() right?
function () {
QScopedPointer<QFile> item(new QFile("filename"));
SomeClassObject->doStuff(item.data());
item.take();
}
---------------------------------
SomeClass::doStuff(QIODevice *item) {
_currentObject = new MyObject(item); // should _currentObject be a smartpointer?
...
}
---------------------------------
class MyObject {
QPointer<QIODevice> _item;
...
MyObject(QIODevice *item) { _item = item; }
}
So I want a way to store pointers and a way to handle them during creation if "new" throws an exception.
The point of shared pointers (and other similar wrappers for pointers) is to handle destruction of the pointer-to object properly. That is instead of having to manually make sure you delete the last copy (and only the last copy), the shared pointer takes care of it for you when it goes out of scope. The shared part means that you can create copies of this wrapper object (the shared pointer object) and it will "share" the pointer-to object between the copies (just as if you made a copy of a regular pointer) with the added benefit described above.
As for your code, SomeClass::doStuff() should have a QScopedPointer<QFile> parameter (instead of a QIODevice* one) as you are passing item to it, which has that type.
Same with MyObject's constructor: have it take a parameter of QPointer<QIODevice> or QSharedPointer<QIODevice> type. In general, everywhere where you would use pointers, use QSharedPointer instead (with the appropriate template type). This will save you from headaches related to accessing deleted objects later on.
Of course, sometimes you actually need the raw QIODevice pointer (e.g. for third-party library call), then you would use the data() member function of the shared pointer object. Just make sure you do not persist (that is store or otherwise copy beyond what's necessary) the returned raw pointer, because that will undercut the purpose of the shared pointers -- the shared pointers will not know about your extra raw pointer that is not under the management of the shared pointer objects.
EDIT:
take() releases the ownership of the pointed-to object from a scoped pointer, so when the scoped pointer is destroyed, it does not delete the object. You would ant ot use it in a situation when you transfered ownership to somthing else -- like in your case to MyObject.
Related
In my main I have variables:
ProcessManager mng;
MemoryManager mem;
dysk disk;
and I'm trying to use these pointers (also in main)
std::shared_ptr<MemoryManager> wsk= std::make_shared<MemoryManager>(mem) ;
std::shared_ptr<dysk> wsk_d = std::make_shared<dysk>(disk);
to pass these objects to an instance of my antoher object (through constructor:
Interpreter interpreter(wsk,wsk_d);
but it looks like intepreter creates his own instance of disk, why?
class Interpreter
{
private:
std::shared_ptr<PCB> pcb;
std::shared_ptr<MemoryManager> mm;
std::shared_ptr<dysk> disk;
}
That's what std::make_shared does: Create a new object using the passed arguments to pass to a suitable constructor. In your case a copy-constructor.
That is, the statement
std::shared_ptr<MemoryManager> wsk= std::make_shared<MemoryManager>(mem);
is equivalent to
std::shared_ptr<MemoryManager> wsk(new MemoryManager(mem));
If you want to have your shared pointer reference the existing object then you need to use e.g.
std::shared_ptr<MemoryManager> wsk(&mem);
But that will bring with it other problems since when the last shared pointer is destructed then it will attempt to free the memory, which is not possible for object not created by new. There are two solutions to this: Either creating a (or using an existing) null-deleter which doesn't actually delete anything; Or by letting the shared pointer handle the complete ownership (from creation to destruction) of the object.
And that's really how you should look at the smart pointers, not as a kind of self-deleting pointer, but in terms of resource ownership.
class myMem{};
class Test{
public:
initMem1(myMem& mInput){/*initialize _mem1*/}
initMem2(shared_ptr<myMem> &pmInput){/*initialize _mem2*/}
myMem _mem1;
shared_ptr<myMem> _mem2;
};
Test myTest;
myTest()
So, in the code above, members belong to a class. One member is a value type and another member is a shared_ptr type. Which way is better for a class member? Moreover, I also have the functions to initialize the members. Which way is better?
In general what is the advantage of passing by reference to shared_ptr over passing by reference directly?
The only reason a function should accept a std::shared_ptr as a argument is if it may need to share or modify the ownership of the resource. If not, don't pass a std::shared_ptr.
If the function will definitely need to take shared ownership then it should accept a std::shared_ptr by value. Only accept a std::shared_ptr& if the function may or may not take shared ownership.
If the function does not modify ownership then pass a reference to the resource, not a std::shared_ptr.
See: CppCoreGuidelines: F.7, R.30, R.34, R.35
Let's look inside your functions. For initmem1, the code usually looks like
initMem1(myMem& mInput){ _mem1 = mInput; }
We can see the call of an assignment operator, which usually copies all myMem fields.
For initMem2, there are two cases
1)
initMem2(shared_ptr<myMem> &pmInput){
_mem2 = pmInput;
}
You should use 'initMem2(const shared_ptr &pmInput)'. It's a good style.
We can see the fast initialization here. Just links are copied. But you get ownership sharing. If you change pmInput outside then _mem2 changes too.
No copy cunstructor is needed. Both smart ptrs holds the unique object.
2)
initMem2(const shared_ptr<myMem> &pmInput){ // of course, const
_mem2.reset(*pmInput);
}
You create a new shared_ptr with new content originally copied from pmInput.
You can change pmInput and _mem2 independently. But you get additional "new/delete calls" for this new shared_ptr and the copy constructor call.
One use case is when the original shared_ptr can change its contents in the middle of the function (perhaps a nested call) and the function is prepared to it and wants the new contents.
With respect to smart pointers and new C++11/14 features, I am wondering what the best-practice return values and function parameter types would be for classes that have these facilities:
A factory function (outside of the class) that creates objects and returns them to users of the class. (For example opening a document and returning an object that can be used to access the content.)
Utility functions that accept objects from the factory functions, use them, but do not take ownership. (For example a function that counts the number of words in the document.)
Functions that keep a reference to the object after they return (like a UI component that takes a copy of the object so it can draw the content on the screen as needed.)
What would the best return type be for the factory function?
If it's a raw pointer the user will have to delete it correctly which is problematic.
If it returns a unique_ptr<> then the user can't share it if they want to.
If it's a shared_ptr<> then will I have to pass around shared_ptr<> types everywhere? This is what I'm doing now and it's causing problems as I'm getting cyclic references, preventing objects from being destroyed automatically.
What is the best parameter type for the utility function?
I imagine passing by reference will avoid incrementing a smart pointer reference count unnecessarily, but are there any drawbacks of this? The main one that comes to mind is that it prevents me from passing derived classes to functions taking parameters of the base-class type.
Is there some way that I can make it clear to the caller that it will NOT copy the object? (Ideally so that the code will not compile if the function body does try to copy the object.)
Is there a way to make it independent of the type of smart pointer in use? (Maybe taking a raw pointer?)
Is it possible to have a const parameter to make it clear the function will not modify the object, without breaking smart pointer compatibility?
What is the best parameter type for the function that keeps a reference to the object?
I'm guessing shared_ptr<> is the only option here, which probably means the factory class must return a shared_ptr<> also, right?
Here is some code that compiles and hopefully illustrates the main points.
#include <iostream>
#include <memory>
struct Document {
std::string content;
};
struct UI {
std::shared_ptr<Document> doc;
// This function is not copying the object, but holding a
// reference to it to make sure it doesn't get destroyed.
void setDocument(std::shared_ptr<Document> newDoc) {
this->doc = newDoc;
}
void redraw() {
// do something with this->doc
}
};
// This function does not need to take a copy of the Document, so it
// should access it as efficiently as possible. At the moment it
// creates a whole new shared_ptr object which I feel is inefficient,
// but passing by reference does not work.
// It should also take a const parameter as it isn't modifying the
// object.
int charCount(std::shared_ptr<Document> doc)
{
// I realise this should be a member function inside Document, but
// this is for illustrative purposes.
return doc->content.length();
}
// This function is the same as charCount() but it does modify the
// object.
void appendText(std::shared_ptr<Document> doc)
{
doc->content.append("hello");
return;
}
// Create a derived type that the code above does not know about.
struct TextDocument: public Document {};
std::shared_ptr<TextDocument> createTextDocument()
{
return std::shared_ptr<TextDocument>(new TextDocument());
}
int main(void)
{
UI display;
// Use the factory function to create an instance. As a user of
// this class I don't want to have to worry about deleting the
// instance, but I don't really care what type it is, as long as
// it doesn't stop me from using it the way I need to.
auto doc = createTextDocument();
// Share the instance with the UI, which takes a copy of it for
// later use.
display.setDocument(doc);
// Use a free function which modifies the object.
appendText(doc);
// Use a free function which doesn't modify the object.
std::cout << "Your document has " << charCount(doc)
<< " characters.\n";
return 0;
}
I'll answer in reverse order so to begin with the simple cases.
Utility functions that accept objects from the factory functions, use them, but do not take ownership. (For example a function that counts the number of words in the document.)
If you are calling a factory function, you are always taking ownership of the created object by the very definition of a factory function. I think what you mean is that some other client first obtains an object from the factory and then wishes to pass it to the utility function that does not take ownership itself.
In this case, the utility function should not care at all how ownership of the object it operates on is managed. It should simply accept a (probably const) reference or – if “no object” is a valid condition – a non-owning raw pointer. This will minimize the coupling between your interfaces and make the utility function most flexible.
Functions that keep a reference to the object after they return (like a UI component that takes a copy of the object so it can draw the content on the screen as needed.)
These should take a std::shared_ptr by value. This makes it clear from the function's signature that they take shared ownership of the argument.
Sometimes, it can also be meaningful to have a function that takes unique ownership of its argument (constructors come to mind). Those should take a std::unique_ptr by value (or by rvalue reference) which will also make the semantics clear from the signature.
A factory function (outside of the class) that creates objects and returns them to users of the class. (For example opening a document and returning an object that can be used to access the content.)
This is the difficult one as there are good arguments for both, std::unique_ptr and std::shared_ptr. The only thing clear is that returning an owning raw pointer is no good.
Returning a std::unique_ptr is lightweight (no overhead compared to returning a raw pointer) and conveys the correct semantics of a factory function. Whoever called the function obtains exclusive ownership over the fabricated object. If needed, the client can construct a std::shared_ptr out of a std::unique_ptr at the cost of a dynamic memory allocation.
On the other hand, if the client is going to need a std::shared_ptr anyway, it would be more efficient to have the factory use std::make_shared to avoid the additional dynamic memory allocation. Also, there are situations where you simply must use a std::shared_ptr for example, if the destructor of the managed object is non-virtual and the smart pointer is to be converted to a smart pointer to a base class. But a std::shared_ptr has more overhead than a std::unique_ptr so if the latter is sufficient, we would rather avoid that if possible.
So in conclusion, I'd come up with the following guideline:
If you need a custom deleter, return a std::shared_ptr.
Else, if you think that most of your clients are going to need a std::shared_ptr anyway, utilize the optimization potential of std::make_shared.
Else, return a std::unique_ptr.
Of course, you could avoid the problem by providing two factory functions, one that returns a std::unique_ptr and one that returns a std::shared_ptr so each client can use what best fits its needs. If you need this frequently, I guess you can abstract most of the redundancy away with some clever template meta-programming.
What would the best return type be for the factory function?
unique_ptr would be best. It prevents accidental leaks, and the user can release ownership from the pointer, or transfer ownership to a shared_ptr (which has a constructor for that very purpose), if they want to use a different ownership scheme.
What is the best parameter type for the utility function?
A reference, unless the program flow is so convoluted that the object might be destroyed during the function call, in which case shared_ptr or weak_ptr. (In either case, it can refer to a base class, and add const qualifiers, if you want that.)
What is the best parameter type for the function that keeps a reference to the object?
shared_ptr or unique_ptr, if you want it to take responsibility for the object's lifetime and not otherwise worry about it. A raw pointer or reference, if you can (simply and reliably) arrange for the object to outlive everything that uses it.
Most of the other answers cover this, but #T.C. linked to a few really good guidelines which I'd like to summarise here:
Factory function
A factory that produces a reference type should return a unique_ptr by default, or a shared_ptr if ownership is to be shared with the factory.
-- GotW #90
As others have pointed out, you as the recipient of the unique_ptr can convert it to a shared_ptr if you wish.
Function parameters
Don’t pass a smart pointer as a function parameter unless you want to use or manipulate the smart pointer itself, such as to share or transfer ownership.
Prefer passing objects by value, *, or &, not by smart pointer.
-- GotW #91
This is because when you pass by smart pointer, you increment the reference counter at the start of the function, and decrement it at the end. These are atomic operations, which require synchronisation across multiple threads/processors, so in heavily multithreaded code the speed penalty can be quite high.
When you're in the function the object is not going to disappear because the caller still holds a reference to it (and can't do anything with the object until your function returns) so incrementing the reference count is pointless if you're not going to keep a copy of the object after the function returns.
For functions that don't take ownership of the object:
Use a * if you need to express null (no object), otherwise prefer to use a &; and if the object is input-only, write const widget* or const widget&.
-- GotW #91
This doesn't force your caller to use a particular smart pointer type - any smart pointer can be converted into a normal pointer or a reference. So if your function doesn't need to keep a copy of the object or take ownership of it, use a raw pointer. As above, the object won't disappear in the middle of your function because the caller is still holding on to it (except in special circumstances, which you would already be aware of if this is an issue for you.)
For functions that do take ownership of the object:
Express a “sink” function using a by-value unique_ptr parameter.
void f( unique_ptr<widget> );
-- GotW #91
This makes it clear the function takes ownership of the object, and it's possible to pass raw pointers to it that you might have from legacy code.
For functions that take shared ownership of the object:
Express that a function will store and share ownership of a heap object using a by-value shared_ptr parameter.
-- GotW #91
I think these guidelines are very useful. Read the pages the quotes came from for more background and in-depth explanation, it's worth it.
I would return a unique_ptr by value in most situations. Most resources shouldn't be shared, since that makes it hard to reason about their lifetimes. You can usually write your code in such a way to avoid shared ownership. In any case, you can make a shared_ptr from the unique_ptr, so it's not like you're limiting your options.
I try to implement a JSON framework in C++ and want to make use of polymorphic concepts. I have a class JSONNode which is kind of container that stores other JSONNode objects itself and so on. I am doing this with pointers and dynamic allocation. For exception safety I do not want to use new/delete but go with boost shared pointer. A basic scenario for adding an element (a further json object) to a json object looks like this:
typedef boost::shared_ptr<JSONNode> JSONNodePtr;
void JSONNode::Add(JSONNodePtr nodePtr, const std::string& name)
{
this->elements[name] = nodePtr; // store in STL std::map
}
// create and add json object
JSONNodePtr obj(new JSONNode());
JSONNodePtr element(new JSONNode());
obj->Add(element, "firstElement");
For easier use I would rather do it without explicit allocation of element and put the creation of the shared pointer into the class method Add:
void JSONNode::Add(JSONNode* node, const std::string& name)
{
JSONNodePtr nodePtr(node);
this->elements[name] = nodePtr;
}
// create and add json object
...
obj->Add(new JSONNode, "firstElement");
But is that still exception safe? I guess not because the creation of the shared pointer is not immediately done with the allocation of the JSONNode*. What do you think? Or are there other more common ways to implement this?
But is that still exception safe?
No. If the construction of the string to pass as the other argument to Add throws, then the dynamic object may be leaked. It is unspecified which argument is created first.
The original code ensures that the dynamic object is assigned to a smart pointer before anything else happens: the only thing that could fail is the creation of the smart pointer itself, in which case it will delete the object.
Or are there other more common ways to implement this?
It's generally a better idea to use the make_shared function template, rather than using new yourself. Not only does it guarantee exception safety by never exposing a naked pointer, it also makes more efficient use of memory by creating the controlled object and the shared reference count in a single block of memory.
obj->Add(boost::make_shared<JSONNode>(), "firstElement"); // or std:: in C++11
Consider the following example code which I have recently seen in our code base:
void ClassA::ExportAnimation(auto_ptr<CAnimation> animation)
{
... does something
}
// calling method:
void classB::someMethod()
{
auto_ptr<CAnimation> animation (new CAnimation(1,2));
ClassA classAInstance;
classAInstance.ExportAnimation(animation)
... do some more stuff
}
I don't like this - and would rather write it so:
void ClassA::ExportAnimation(CAnimation* animation)
{
... does something
}
// calling method:
void classB::someMethod()
{
auto_ptr<CAnimation> animation (new CAnimation(1,2));
ClassA classAInstance;
classAInstance.ExportAnimation(animation.get())
... do some more stuff
}
but it is really a problem?
It all depends on what ExportAnimation is and how it is implemented.
Does it only use the object for the duration of the call and then leaves it?
Then convert to a reference and pass a real reference. There is no need to pass membership and the argument is not optional, so void ExportAnimation( CAnimation const & ) suffices. The advantage is that it is clear from the interface that there is no memory management issues with the method, it will just use the passed object and leave it as such. In this case, passing a raw pointer (as in your proposed code) is much worse than passing a reference in that it is not clear whether ExportAnimation is or not responsible for deletion of the passed in object.
Does it keep the object for later use?
This could be the case if the function starts a thread to export the animation in the background. In this case, it has to be clear that the lifetime of the argument must extend beyond the duration of the call. This can be solved by using shared_ptr --both in the function and outside of it-- as they convey the object is shared and will be kept alive as much as required meaning. Or else you can actually transfer ownership.
In the later case, if transfer of ownership is performed, then the initial code is fine --the signature is explicit in the ownership transfer. Else you can opt to document the behavior, change to a raw pointer and make the transfer explicit by calling ExportAnimation( myAnimation.release() ).
You have added some concerns as a comment to another answer:
can I really see that object no longer exists after the method call?
The caller auto_ptr is reset to 0 in the call, so any dereference will kill be an error and will be flagged in the first test you try.
I would need to look at the header file to see that the parameter type is an auto_ptr and not a normal pointer.
You do not need to look at the header... just try passing a raw pointer and the compiler will tell you that it requires an auto_ptr<> --There is no implicit conversion from raw pointer to auto_ptr.
I would expect the object to exist until the auto_ptr goes out of scope.
The standard auto_ptr, unlike boost::scope_ptr, do not have that semantics. The ownership of the object can be released or passed to other auto_ptr, so the assumption that an object held in an auto_ptr lives for the whole scope of the auto_ptr is bad in itself.
The auto_ptr unambiguously declares that the ownership of the pointer is passed on. The plain pointer isn't self-documenting.
What is the point of an auto-ptr if you only use its internals as a storage location?
Yes, pass it to the function. Or do away with it entirely, if you really don't want it. Presumably the function needs it to pass along ownership to something else.
It sounds like maybe the alternative you're looking for is much simpler:
void ClassA::ExportAnimation(CAnimation &animation) // no pointer
// calling method:
void classB::someMethod()
{
CAnimation animation(1,2); // no pointer
ClassA classAInstance;
classAInstance.ExportAnimation(animation) // no ownership tranfer
... do some more stuff
// object dies here, no earlier, no later
}
Passing the smart pointer to ExportAnimation clearly documents, and enforces, that ownership has been passed to the function, and there is no need for the caller to delete the animation. The function will also not need to explicitly delete the object, just let the pointer go out of scope.
Your suggestion leaves that ambigious; should ExportAnimation delete the object you've passed via raw pointer? You'd need to check the function's documentation to know what the caller should do, and also check the implementation to make sure it's actually implemented as documented.
I would always recommend using smart pointers (and other RAII idioms) to make object lifetime explicit and automatic.