shared pointer and raw pointer lifetime - c++

Could someone explain simply the reason why this does not work:
std::shared_pointer<Bar> getSharedPointer() {
return std::make_shared<Bar>();
}
...
auto foo = getSharedPointer().get();
Apparently using the raw pointer foo will cause a segfault because the lifetime of the shared pointer returned by getSharedPointer() will have run out. Somehow I would expect it to last until the end of its scope (like whatever block it is inside).
Is this correct and are there any analogous examples to this situation?

For getSharedPointer().get();, getSharedPointer() returns a temporary std::shared_ptr which will be destroyed after the expression immediately, and the pointer managed by it will be deleted too. After that foo will become dangled, any dereference on it causes UB.
auto foo = getSharedPointer().get();
// foo have become dangled from here
You could use a named variable instead:
auto spb = getSharedPointer();
auto foo = spb.get();
// It's fine to use foo now, but still need to note its lifetime
// because spb will be destroyed when get out of its scope
// and the pointer being managed will be deleted too

auto foo = getSharedPointer().get();
Whenever a function returns a type that is not a reference, the result of calling the function is an rvalue. Also, because the function getSharedPointer() returns a class type, the result is a temporary object.
The lifetime of that temporary object is defined as the end of the evaluation of the outermost expression, here getSharedPointer().get(). As soon as the foo variable is initialized, the owning smart pointer is destroyed; when the last shared_ptr owning that object is destroyed, the object is deleted.
Here getSharedPointer() always returns shared_ptr that doesn't share the managed object (use_count() is 1), so when that copy of the last shared_ptr is destroyed, the object is destroyed and the pointer to the object is invalid.
(I am not sure why you are returning a shared_ptr and not a unique_ptr here.)
The proper use of a smart pointer, or any class that "owns" (controls the lifetime of) other resources (resources that you are still allowed to access directly), is to keep the "smart" pointer/owner alive as long as you need to access the ressource.
So the "smart" pointer (owning object) needs to be named. Also, I am not sure that you really would want to hide the fact that it is a smart pointer from the view of the reader with auto.
std::shared_pointer<Bar> foo = getSharedPointer();
// use foo.get()
You may want to hide the exact type of managed object:
std::shared_pointer<auto> foo = getSharedPointer();

Related

How to assign the shared_ptr object to the function of type raw pointer using C++

I am creating the shared_ptr in a function and returning raw pointer from that function.
To get the underlying raw pointer from the shared_ptr I am using .get()
If i am using the raw pointer in a function and assigning to the function of type raw pointer it is working without any issue.
But if i create the shared_ptr and while returning, it is calling the destructor and deleting the memory assigned to the object and crashing.
How to assign the shared_ptr object to the function of type raw pointer?
CMyClass::CMyClass()
{
}
CMyClass::~CMyClass()
{
}
CMyClass* CreateClassInstance()
{
std::shared_ptr<CMyClass> l_MyClassInterface = std::make_shared<CMyClass>();
return l_MyClassInterface.get();
}
CMyClass* CreateClassInstance()
{
CMyClass* l_MyClassInterface = new CMyClass();
return l_MyClassInterface;
}
auto l_pMyClassInterface = CreateClassInstance();
Yes, what #user17732522 said.
In the code as written, l_MyClassInterface is going out of scope when your first version of CreateClassInstance returns, taking your newly created object with it. When you return a shared_ptr, as opposed to the pointer returned by get(), the mechanism that it uses to keep track of the reference count for your object kicks in and stops that from happening. (Well, in principle. In practise, copy elision usually / always ensures that the shared_ptr created by make_shared is returned directly to the caller, but that's a detail.)
The other (inferior) solution would be to return the pointer returned by new directly and assign it to a shared_ptr in the caller. But that is error-prone, and not recommended.

lifetime of an object managed by const std::unique_ptr

I see below notes in std::unique_ptr reference:
Only non-const unique_ptr can transfer the ownership of the managed object to another unique_ptr. The lifetime of an object managed by const std::unique_ptr is limited to the scope in which the pointer was created.
Is there anyone who can explain it with an example? I could not figure it out why.
You simply can not move from a const std::unique_ptr and you can't use other modifying member functions - swap, release and reset either (these are logically non-const qualified, cannot be called on a const instance).
Transferring ownership implies resetting the old owner to non-owning state, thus modifying it.
const std::unique_ptr will manage at most one object during its lifetime (starting from its initialization).In case of std::unique_ptr const&, you won't be able to transfer ownership from the referenced (even non-const) std::unique_ptr through this reference (const correctness).
The reset, release, swap, and move assignment functions are non-const member functions and therefore cannot be used with a const instance of the std::unique_ptr class. Therefore, a const std::unique_ptr has no way of being modified and is forced to own the pointer until it goes out of scope.
Normally you can transfer ownership of a managed object to another unique_ptr by using move assignment or the move constructor, e.g.:
std::unique_ptr<int> p(new int(1));
std::unique_ptr<int> q(std::move(p));
//now q owns the pointer, which is freed when q is destructed
But if p was const, you wouldn't be able to do so, and the managed object will be freed when p is destructed:
const std::unique_ptr<int> p(new int(1));
std::unique_ptr<int> q(std::move(p)); //compilation error
A unique_ptr owns the memory that it points at.
void MyFunc()
{
// Creates a unique pointer that points at a Foo object.
std::unique_ptr<Foo> foo = std::make_unique<Foo>();
// ... do some stuff, then return
}
In this example, we create a Foo object and assign it to our unique_ptr. Normally when you create something that's on the heap, you have to use new allocate space for it in the heap and construct it, and delete to destruct it and deallocate its space. Here, the unique_ptr handles deallocation as soon as you leave the scope where the unique_ptr was created (which in this case is the end of the function).
Only non-const unique_ptr can transfer the ownership of the managed object to another unique_ptr.
This means you can transfer the ownership of your pointer to a different unique_ptr, but only if it's not marked as const. Only one unique_ptr can own an object at a time.
One way to do that would be like this:
std::unique_ptr<Foo> foo1 = std::make_unique<Foo>();
std::unique_ptr<Foo> foo2 = std::move(foo1);
Now the pointer in foo1 has been moved to foo2. foo1 is no longer managing that memory, foo2 is.
The lifetime of an object managed by const std::unique_ptr is limited to the scope in which the pointer was created.
This means that when your unique_ptr leaves scope, it deletes the object that it points to. It's as if you did this:
void MyFunc()
{
Foo* foo = new Foo()
// ... do some stuff, then return
delete foo;
}
The benefit is that now you don't have to manually call delete, which is good because that's a potential memory leak if you forget to delete it.

Return by reference in C++ - Reference assignment vs value assignment

Suppose I have:
class SomeObject {
};
SomeObject& f() {
SomeObject *s = new SomeObject();
return *s;
}
// Variant 1
int main() {
SomeObject& s = f();
// Do something with s
}
// Variant 2
int main() {
SomeObject s = f();
// Do something with s
}
Is there any difference between the first variant and the second? any cases I would use one over the other?
Edit: One more question, what does s contain in both cases?
First, you never want to return a reference to an object which
was dynamically allocated in the function. This is a memory
leak waiting to happen.
Beyond that, it depends on the semantics of the object, and what
you are doing. Using the reference (variant 1) allows
modification of the object it refers to, so that some other
function will see the modified value. Declaring a value
(variant 2) means that you have your own local copy, and any
modifications, etc. will be to it, and not to the object
referred to in the function return.
Typically, if a function returns a reference to a non-const,
it's because it expects the value to be modified; a typical
example would be something like std::vector<>::operator[],
where an expression like:
v[i] = 42;
is expected to modify the element in the vector. If this is
not the case, then the function should return a value, not
a reference (and you should almost never use such a function to
initialize a local reference). And of course, this only makes
sense if you return a reference to something that is accessible
elsewhere; either a global variable or (far more likely) data
owned by the class of which the function is a member.
In the first variant you attach a reference directly to a dynamically allocated object. This is a rather unorthodox way to own dynamic memory (a pointer would be better suited for that purpose), but still it gives you the opportunity to properly deallocate that object. I.e. at the end of your first main you can do
delete &s;
In the second variant you lose the reference, i.e. you lose the only link to that dynamically allocated object. The object becomes a memory leak.
Again, owning a dynamically allocated object through a reference does not strike me as a good practice. It is usually better to use a pointer or a smart pointer for that purpose. For that reason, both of your variants are flawed, even though the first one is formally redeemable.
Variant 1 will copy the address of the object and will be fast
Variant 2 will copy the whole object and will be slow (as already pointed out in Variant2 you cant delete the object which you created by calling new)
for the edit: Both f contain the same Object
None of the two options you asked about is very good. In this particular case you should use shared_ptr or unique_ptr, or auto_ptr if you use older C++ compilers, and change the function so it returns pointer, not reference. Another good option is returning the object by value, especially if the object is small and cheap to construct.
Modification to return the object by value:
SomeObject f() { return SomeObject(); }
SomeObject s(f());
Simple, clean, safe - no memory leaking here.
Using unique_ptr:
SomeObject* f() { return new SomeObject(); }
unique_ptr<SomeObject> s(f());
One of the advantages of using a unique_ptr or shared_ptr here is that you can change your function f at some point to return objects of a class derived from SomeObject and none of your client code will need to be changed - just make sure the base class (SomeObject) has a virtual constructor.
Why the options you were considering are not very good:
Variant 1:
SomeObject& s = f();
How are you going to destroy the object? You will need address of the object to call it's destructor anyway, so at some point you would need to dereference the object that s refers to (&s)
Variant 2. You have a leak here and not a chance to call destructor of the object returned from your function.

When using shared_ptr should I just use the shared_ptr declaration once or declare shared_ptr everywhere I pass it?

When using shared_ptr, should I just use the shared_ptr declaration once or declare shared_ptr everywhere I pass it?
So in the function where I new up the instance I wrap it in a shared_ptr but when I return it from the function I could also return a shared_ptr or, using the get() on the shared_ptr, just return a normal pointer.
So my question is, should I just use shared_ptr<myType> when I new the instance and then pass normal pointers around or should I be passing shared_ptr<myType> everywhere?
Creating a shared_ptr doesn't imbue magical powers on its pointee object. The magic is all in the shared_ptr — and its copies — itself. If you stop using it, you lose your reference counting; worse, because you used it at some point, the object will be automatically deleted when you don't expect it.
The whole point of having shared_ptr is that you know your object won't get destroyed when you're still using it somewhere.
In the following:
T* foo() {
shared_ptr<T> sp(new T());
return sp.get();
// ^ the only shared_ptr<T> referencing the obj is dead;
// obj is deleted;
// returned pointer invalid before you can even do anything with it
}
your pointer is immediately invalid.
There may well be circumstances in which you extract a raw pointer, but these should be rare. If you are in a function where you know you don't need the reference counting, then just pass the shared_ptr in by reference.

shared_ptr deletes the object

void ClassName::LocalMethod( )
{
boost::shared_ptr<ClassName> classNamePtr( this );
//some operation with classNamePtr
return;
}
Here the object is getting released when it returns from LocalMethod() since classNamePtr is out of scope. Isn't the shared_ptr smart enough to know that the ClassName object is still in scope and not to delete it?
What does it mean to create a shared_ptr to an object? It means that the holder of the shared_ptr now assumes ownership over the object. Ownership meaning that the object will be deleted when he so desires. When the holder of the shared_ptr destroys its shared_ptr, that will cause the object to potentially be destroyed, assuming that there are no other shared_ptrs to that object.
When a shared_ptr is a member of a class, that means that the lifetime of the object pointed to by the shared_ptr is at least as long as the object that the shared_ptr is a member of. When a shared_ptr is on the stack, this means that the lifetime of the object that the shared_ptr is pointing to will be at least as long as the scope it was created in. Once the object falls off the stack, it may be deleted.
The only time you should ever take a pointer and wrap it into a shared_ptr is when you are allocating the object initially. Why? Because an object does not know whether it is in a shared_ptr or not. It can't know. This means that the person who creates the original shared_ptr now has the responsibility to pass it around to other people who need to share ownership of that memory. The only way shared ownership works is through the copy constructor of shared_ptr. For example:
shared_ptr<int> p1 = new int(12);
shared_ptr<int> p2 = p1.get();
shared_ptr<int> p3 = p1;
The copy constructor of shared_ptr creates shared ownership between p1 and p3. Note that p2 does not share ownership with p1. They both think they have ownership over the same memory, but that's not the same as sharing it. Because they both think that they have unique ownership of it.
Therefore, when the three pointers are destroyed, the following will happen. First, p3 will be destroyed. But since p3 and p1 share ownership of the integer, the integer will not be destroyed yet. Next, p2 will be destroyed. Since it thinks that it is the only holder of the integer, it will then destroy it.
At this point, p1 is pointing to deleted memory. When p1 is destroyed, it thinks that it is the only holder of the integer, so it will then destroy it. This is bad, since it was already destroyed.
Your problem is this. You are inside an instance of a class. And you need to call some functions of yours that take a shared_ptr. But all you have is this, which is a regular pointer. What do you do?
You're going to get some examples that suggest enable_shared_from_this. But consider a more relevant question: "why do those functions take a shared_ptr as an argument?"
The type of pointer a function takes is indicative of what that function does with its argument. If a function takes a shared_ptr, that means that it needs to own the pointer. It needs to take shared ownership of the memory. So, look at your code and ask whether those functions truly need to take ownership of the memory. Are they storing the shared_ptr somewhere long-term (ie: in an object), or are they just using them for the duration of the function call?
If it's the latter, then the functions should take a naked pointer, not a shared_ptr. That way, they cannot claim ownership. Your interface is then self-documenting: the pointer type explains ownership.
However, it is possible that you could be calling functions that truly do need to take shared ownership. Then you need to use enable_shared_from_this. First, your class needs to be derived from enable_shared_from_this. Then, in the function:
void ClassName::LocalMethod()
{
boost::shared_ptr<ClassName> classNamePtr(shared_from_this());
//some operation with classNamePtr
return;
}
Note that there is a cost here. enable_shared_from_this puts a boost::weak_ptr in the class. But there is no virtual overhead or somesuch; it doesn't make the class virtual. enable_shared_from_this is a template, so you have to declare it like this:
class ClassName : public boost::enable_shared_from_this<ClassName>
Isn't the shared_ptr smart enough to know that the ClassName object is
still in scope and not to delete it?
That's not how shared_ptr works. When you pass a pointer while constructing a shared_ptr, the shared_ptr will assume ownership of the pointee (in this case, *this). In other words, the shared_ptr assumes total control over the lifetime of the pointee by virtue of the fact that the shared_ptr now owns it. Because of this, the last shared_ptr owning the pointee will delete it.
If there will be no copies of classNamePtr outside of ClassName::LocalMethod(), you can pass a deleter that does nothing while constructing classNamePtr. Here's an example of a custom deleter being used to prevent a shared_ptr from deleting its pointee. Adapting the example to your situation:
struct null_deleter // Does nothing
{
void operator()(void const*) const {}
};
void ClassName::LocalMethod()
{
// Construct a shared_ptr to this, but make it so that it doesn't
// delete the pointee.
boost::shared_ptr<ClassName> classNamePtr(this, null_deleter());
// Some operation with classNamePtr
// The only shared_ptr here will go away as the stack unwinds,
// but because of the null deleter it won't delete this.
return;
}
You can also use enable_shared_from_this to obtain a shared_ptr from this. Note that the member function shared_from_this() only works if you have an existing shared_ptr already pointing to this.
class ClassName : public enable_shared_from_this<ClassName>
{
public:
void LocalMethod()
{
boost::shared_ptr<ClassName> classNamePtr = shared_from_this();
}
}
// ...
// This must have been declared somewhere...
shared_ptr<ClassName> p(new ClassName);
// before you call this:
p->LocalMethod();
This is the more appropriate, "official" method and it's much less hackish than the null deleter method.
It could also be that you don't actually need to create a shared_ptr in the first place. What goes into the section commented //some operation with classNamePtr? There might be an even better way than the first two ways.