I have a class derived from std::enable_shared_from_this. All class objects are managed by shared pointers, thus they get destructed automatically when there are no more shared pointers pointing to them.
I have a class method which removes some shared pointers from the program's data structures, and there's a risk it removes all shared pointers to "this", i.e. the object on which the class method was called.
The question is, if really all pointers are removed, is there a chance the object is destroyed while the method runs, and the "this" pointer simply becomes invalid? If I want to ensure it doesn't happen, can I trust the system or I have to create a shared_ptr to "this" inside the method, to keep the object alive until I'm done with it? (And then if there's no more pointers, it's okay to have it destructed, once the method execution ends)
EXAMPLE:
class SharedObj : public std::enable_shared_from_this<SharedObj>
{
/* ... */
void do_something(SharedObj& a, SharedObj& b);
std::shared_ptr<SharedObj> child;
};
void SharedObj::do_something(SharedObj& a, SharedObj &b)
{
/* ... */
a.remove_child();
b.remove_child();
}
If a and b are the only ones who have a shared_ptr pointing to "this", then after the two remove_child() rows, there are no shared pointers pointing to "this", so besically it's supposed to be automatically destructed
You certainly can wind up destructing your instance from within a method by doing what you're doing. But this situation isn't specific to enable_shared_from_this, you can always call something in a method that can result in your own class's destruction. This is really only an error if you try to deference this after your class is destroyed. If you go on with regular code that doesn't modify or access the class instance, you are safe.
What you suggested (to hold a shared_ptr to your own instance during do_something's execution) is a good idea, if you need the instance to persist for the entire function execution.
As an alternative or in addition to Dave's answer if you are using shared pointers throughout for managing lifetimes then you should only ever be calling the object through a shared pointer anyway so that pointer will be keeping the object alive until after the function returns. If you store a non-owning pointer to a shared pointer managed object then you should be storing a weak pointer and locking it before using it. That shared pointer created by locking will again keep the object alive.
Related
In my method a Player object is created like:
Player player(fullName,age);
My teacher gave us a piece of code with a constructor that takes a shared_ptr to a player object.
//constructor of the class
SomeClass(const std::shared_ptr<Socket> client, std::shared_ptr<Player> player)
Lets say we want to call the constructor of SomeClass and pass the player object we created on stack.
Is it ever safe/possible/good to create a shared_ptr from a stack object?
To make the question more understandable lets say we have two big code projects and we want to merge them so a method from one project is called from another one, should we rewrite all the files to use shared_ptr or stack objects exclusivly (for the methods that needs to be connected) or should we just create a shared_ptr to the stack object.
Why im not sure of the result:
What if the scope where the stackobject is created ends but the shared_ptr is still used and vise versa.
The stackobject gets deleted when out of scope or does it stay alive because there is still a reference to the object (in another class though)?
The shared_ptr goes out of scope and tries to delete the object, can it even though the stackobject is refering to it?
Note: I know I could just use the following and pass player
shared_ptr<Player> player{ new Player {fullName,age} };
Is it ever safe/possible/good to create a smart_ptr from a stack object?
Safe? Only if you can guarantee that the stack which created that object will only be ended after all shared_ptr's that pseudo-own it.
Possible? Sure: pass shared_ptr's constructor a deleter object that does nothing:
auto sptr = shared_ptr<Player>(&player, [](Player *) {});
When the last shared_ptr is destroyed, the deleter will be called and nothing will be deleted.
Good? Not really. As noted above, safety is not something that can be universally guaranteed in such code. Depending on your code structure, this may be legitimate. But it requires great care.
This SomeClass is expecting to claim ownership of a resource; that's why it's taking a shared_ptr. You're kind of lying to it by passing it a shared_ptr that doesn't really own the object it references. That means the onus is on you and your code structure to not violate the promise you made to SomeClass that it would have shared control over that object's lifetime.
The purpose of a shared pointer is to manage the lifetimes of dynamically created objects. As long as there is any shared pointer that points at an object, that object must still exist; when the last shared pointer that points at an object is destroyed, that object gets destroyed.
Stack objects have a fundamentally different lifetime: they exist until the code exits from the scope in which they were created, and then they are destroyed.
The two notions of lifetime are incompatible: there is no way a shared pointer can ensure that a stack object that has gone out of scope still exists.
So don't mix the two.
Is it ever safe/possible/good to create a shared_ptr from a stack object?
I agree with #Nicolas Bolas that it is not safe. But it may be safe to create a shared_ptr from a copy of a stack object
shared_ptr<Player> playerPtr(new Player(player));
if Player is copy-able of course.
It's not safe to create a shared pointer to a stack object, because the stack object is due for destruction as soon as its containing function returns. Local objects are allocated and deallocated implicitly and automatically and trying to intervene is surely invoking many kinds of undefined behavior.
Use move semantics to create the shared_ptr
std::shared_ptr<Player> player_shared_ptr{ std::make_shared(std::move(player)) };
In this way, a copy is avoided. You may need to implement move constructor though on relevant classes for this approach to work. Most/all std objects support move semantics out of the box (eg. string, vector, etc.)
Safe is a strong word.
However, You can make the code safer by defining a StackObjectSharedPtr, forcing the shared_ptr instanciated type to include a "special" StackObjectDeleter
using PlayerStackSP = std::shared_ptr <Player, StackObjectDeleter> ;
class StackObjectDeleter {
public:
void operator () (void*) const {}
};
Player player(fullName,age);
std::shared_ptr<PlayerStackSP, StackObjectDeleter> player(&player, StackObjectDeleter());
The StackObjectDeleter replaces the default_delete as the deleter object. default_delete simply calls delete (or delete []). In case of StackObjectDeleter, nothing will happen.
This is a step further of #Nicol Bolas's answer.
If we have a Parent class that has a reference to a Child Class (shared pointer) and the Child Class also has a reference to the Parent Class (again with a shared pointer) we have to make one of these two smart pointers a weak pointer.
But how we decide which of these two pointers should be a weak pointer?
Also when a weak pointer points to 0 (when the shared count is 0), is not a situation where an object deleted when we may still need access to it? ok, i get that at least we know that the object is not there and that we should not try to access it, but is this enough?
Think about the liftime of the objects.
If the Child can't out-live the Parent, then the Parent hold a shared pointer to the Child.
Shared pointers define the life-time hierarchy.
If we have a Parent class that has a reference to a Child Class
(shared pointer) and the Child Class also has a reference to the
Parent Class (again with a shared pointer) we have to make one of
these two smart pointers a weak pointer.
No, you don't have to, you can if you think it will suits your design.
But how we decide which of these two pointers should be a weak
pointer?
The object that can live and do his job without needing the other should store the weak pointer
Also when a weak pointer points to 0 (when the shared count is 0), is
not a situation where an object deleted when we may still need access
to it? ok, i get that at least we know that the object is not there
and that we should not try to access it, but is this enough?
If both object need each other to be alive when they are alive themselves, then keep a shared pointer in each of them. When these objects are done doing their job you just have to reset one shared pointer (usually the one contained in the most top level class) and it will create a cleaning cycle where all your instances are correctly destroyed if they are not used elsewhere.
P.S: A design I find very helpful for this situations is to add start/stop member functions especially if you are using enable_shared_from_thiswhich can't be called within the constructor, you can get more details on this design from boost asio's author.
In my library, I use std:shared_ptr`s to hold communication objects, I am working with. I have template function creating those pointers. It returns raw pointers so application could use those objects, without overhead with reference counting (strict realtime application).
template<typename COBTYPE>
inline COBTYPE* CLink::createCob(COBTYPE cob) {
std::shared_ptr<CCob> c(cob);
if(c->init(this)!=OK){
trace(ERROR,"Cannot add cob, failed to initialize\n");
return NULL;
}
mCobs.push_back(c); //vector of my pointers
return (COBTYPE*) c.get();
}
I am in doubt, when the object will be deleted, if I call function as
link.createCob(new CobOfSomeTypo cob()) ?
Will use of shared_ptr prevent delete of cob object when it will have to pop from stack?
Is this concept good?
The object of which a shared pointer shares ownership is deleted when there are no more shared pointers sharing ownership, e.g. typically in the destructor of some shared pointer (but also in an assignment, or upon explicit reset).
(Note that there may be shared pointers of many different types sharing ownership of the same object!)
That said, your code has issues. Perhaps it might be better like this:
// Requirement: C must be convertible to CCob
template <typename C>
C * CLink::createCob()
{
auto p = std::make_shared<C>();
if (p->init(this) != OK) { return nullptr; }
mCobs.push_back(std::move(p));
return mCobs.back().get();
}
The usage would then be: link.createCob<CobOfSomeTypo>(). It depends, though, on whether you need to be able to take ownership of existing pointers. That itself would be something worth fixing, though.
It's also possible (but impossible to tell from your question) that you dont actually need shared pointers at all and could simply work with unique pointers.
From this reference, the object is deleted when one of the following is true.
the last remaining shared_ptr owning the object is destroyed.
the last remaining shared_ptr owning the object is assigned another pointer via operator= or reset().
With respect to your specific situation, when the shared pointer is popped off the stack, if that is the last one referencing the object, then the object is destroyed when the popped-off element goes out of scope.
Note that if you extract a raw pointer to the same object and explicitly delete the object first, then you are invoking undefined behavior because delete may be called twice on the same object.
Will the smart pointer or scoped pointers delete an object when the class has no destructor
If not, why not just leave the scope and let the object be deleted by itself?
All class members are deleted even if you don't have a destructor when the instance is deleted. Memory leaks occur when you deal with pointers:
class A
{
private:
B* b;
};
In this case, b itself will be destroyed when the instance of A is deleted, but the memory it points to will not.
class A
{
private:
SmartPtr<B> b;
};
In the case of smart pointers, which usually have some reference counting and memory cleanup in the destructor, the memory it points to will be explicitly destroyed by its destructor, and the destructor of the smart pointer will be implicitly called when the instance of the containing class is destroyed.
yes. that s what smart pointers are used for.
http://www.boost.org/doc/libs/1_48_0/libs/smart_ptr/smart_ptr.htm
http://en.wikipedia.org/wiki/Smart_pointer
What is a smart pointer and when should I use one?
Yes, smart pointer deletes the object irrespective of whether class has destructor or not. Note that smart pointers are used with objects allocated on heap (using new) and these object won't release memory when they go out of scope, you need to explicitly delete them. Smart pointers will remove this process of explicitly deleting them.
The pointer to the object itself will be deleted. However if there is any dynamically allocated data in the class it will not get freed. The idea of having a destructor is to be able to post-process the class object and mainly - free any resources taken.
new and delete do two things.
new allocates memory and gets an object to construct itself in that memory space.
delete first gets the object to destruct itself then releases the memory.
Note that some smart pointers can be given a custom deleter which doesn't call delete on the object but whatever you ask it to do. There may be occasions when you wish to pass it a no-op.
Your point is well taken; there aren't that many uses for smart pointers
in C++, since most of the time where they might be relevant, you'd be
better off using value semantics, and copying. In the case of
scoped_ptr, the most frequent use is when the actual object is
polymorphic:
scoped_ptr<Base> pObj = condition
? static_cast<Base*>( new Derived1 )
: static_cast<Base*>( new Derived2 );
(Regretfully, at least one of the static_cast is necessary.)
If you are dealing with a container of polymorphic objects, you'll need
shared_ptr instead, and if you're returning a polymorphic object, or
otherwise passing it around, you will use unique_ptr if you can
guarantee its availability, and auto_ptr otherwise—in some cases
where you're passing it around, shared_ptr might be more appropriate.
In the case of returning an object or passing it around, the cost of
copying it might also be a motive for using a smart pointer, even if the
object isn't polymorphic. In such cases, I'd still use value semantics
(i.e. copying and assigning the object itself) unless I had a
performance problem.
Note that smart pointers aren't only used for memory management. I
regularly use auto_ptr in the interface of queues between threads:
once the object has been inserted into the queue, it no longer belongs
to the sending thread; auto_ptr expresses these semantics exactly,
with the auto_ptr in the sending thread becoming invalid. Or a
modifiable singleton (something which should be very, very rare) might
acquire a lock in its instance function, and return a shared_ptr
which frees the lock in its final destructor. I've also used smart
pointers in one or two cases to ensure transactional semantics: in one
case, for example, the objects were in a number of different sets (which
held pointers to them, of course), ordered according to different
criteria. To modify an object, you acquired a shared pointer to it; the
function which returned this shared pointer also removed the objects
from the sets, so that you could safely modify the key values as well,
and the final destructor reinserted them into the sets according to the
new keys. And so on—there are any number of uses for smart
pointers that have nothing to do with memory management or object
lifetime.
Im working on this project,
The problem Im having is that the an object, does not really get deleted when I need it to be because it has a couple of shared pointers pointing to it.
How do I solve this,please help.
This is by design. As long as an object is owned by one or more shared_ptr smart pointers, it will not be destroyed. Ownership of the object is shared by all of the smart pointers that have ownership and the object can't be destroyed until all of the owners are done with it. This is what shared ownership is.
If you want to be able to destroy the object while there are still some references to it, you can use weak_ptr for those references.
You can decrease the use_count of a shared_ptr by using its reset() method.
If you do this for every pointer which holds the instance, the last reset() will destroy the object it points to.
shared_ptr<Class> myPointer1( new Class() ); //myPointer holds an instance of Class
shared_ptr<Class> myPointer2 = myPointer1; //use_count == 2
myPointer1.reset(); //use_count == 1
myPointer2.reset(); //instance of class will be destroyed
But you probably have a problem with you design, shared_ptr should automatically go out of focus when certain objects are destroyed or methods end. Perhaps you should have a look at the points where the shared_ptrs still hold pointers to the object and check if they shouldn't hold the object anymore.