So I have a shared_ptr in my Main class, and I'd like some other object (a singleton class) to have access to what the shared_ptr is pointing to.
In pseudo code...
mySingletonInstance->somePointer = myShared_ptr;
How do I do that?
If the singleton should participate in shared management of the object that is held by shared_ptr then it's somePointer could be simply a copy of that shared_ptr. Otherwise use a weak_ptr.
If you don't want mySingletonInstance->somePointer to respect the ownership semantics of shared_ptr, then:
class MySingletonClass {
SomeType* somePointer;
}
shared_ptr<SomeType> myShared_ptr;
...
// Then either of the following lines:
mySingletonInstance->somePointer = mySharedPtr.get();
mySingletonInstance->somePointer = &*mySharedPtr;
But beware -- your somePointer might hold a pointer to the object even after it has been deleted.
Related
I'd like to reset a shared_ptr without deleting its object and let weak_ptr of it loses a reference to it. However, shared_ptr doesn't have release() member function for reasons, so I can't directly do it. The easiest solution for this is just to call weak_ptr's reset() but the class which owns the shared_ptr and wants to release it doesn't know which class has weak_ptr of it. How can that be achieved in this case?
I understand why shared_ptr doesn't have release function but unique_ptr. In my case, only one instance owns a pointer, but shared_ptr can be owned by multiple instances and releasing doesn't make sense then. But if shared_ptr doesn't have that function, how can I cut connections to weak_ptr without deleting the object?
shared_ptr<int> A = make_shared<int>(100);
weak_ptr<int> B = A;
// I want something like this! but shared_ptr doesn't have release function..
int* releasedData = A.release();
A.reset(releasedData);
if (shared_ptr<int> C = B.lock)
{
// B already lost a reference, so it should never reach here
}
Background
A shared pointer of a class which stores a pointer of a large array is shared with other classes. The shared pointer is passed as a weak pointer to those, and the owner class of the shared pointer doesn't know about those classes. Multiple instances of the owner class are activated and deactivated at runtime. Because initializing cost of the instance is high, I use object pool pattern: I reuse those instances instead of creating/deleting every time I use it. The problem here is that when an instance of the owner class is deactivated, it should be tread as removed(although it still holds the data), and thus other classes which has a weak reference to the data should lose the reference. Resetting a shared pointer makes it possible, but I don't want to do it because the data is large.
I can make a manager class to keep track of which weak pointer refers to which shared pointer, but I wonder if this can be solved by something else.
std::shared_ptr and std::weak_ptr are made to model the concept of RAII. When you use a std::shared_ptr, you already made the decision that it owns the resource, and that it should release the resource on destruction. The clunkiness you face is due to a rebellion against RAII: you want std::shared_ptr to own the resource but sometimes not really.
The solution is to reframe your object pool as an allocator. Suppose you have
struct obj_t { /* ... */ };
struct pool_t {
obj_t* acquire(); // get an object from the pool
void release(obj_t*); // return the object to the pool
// ...
};
Then your std::shared_ptr will look like
auto d = [&pool](auto p){ pool.release(p); };
std::shared_ptr<obj_t> obj{pool.acquire(), d};
Notably, the resource acquisition always gets paired with its destruction.
Under this model your problem doesn't exist
std::weak_ptr<obj_t> b = obj;
obj = nullptr; // or let obj get destroyed in any other way
if(auto c = b.lock())
// doesn't happen
You may use a shared_ptr with custom deleter that would prevent the object from being destroyed:
shared_ptr<int> A = shared_ptr<int>(new int(100), [](int*){});
weak_ptr<int> B = A;
// Save the pointer that you otherwise would lose:
int* releasedData = A.get();
A = shared_ptr<int>(releasedData, [](int*){});;
if (shared_ptr<int> C = B.lock())
{
// B already lost a reference, so it should never reach here
}
But don't forget to delete the object by any other means. For example:
shared_ptr<int> realOwner(new int(100));
shared_ptr<int> A = shared_ptr<int>(realOwner.get(), [](int*){});
weak_ptr<int> B = A;
Is that an accurate description of it? Does it make sense?
Are you guaranteed that the object it points to won't be deleted until the unique_ptr goes out of scope [even if you're not using the unique_ptr]?
Yes, std::unique_ptr follows the RAII design principle.
No, std::unique_ptr does not prevent other code from doing something stupid, like calling delete on a pointer that belongs to the unique_ptr. The unique_ptr itself will call a deleter1 on the object it owns when either:
it goes out of scope
or
the unique_ptr is reassigned (via operator= or reset) to point to a different object
One can also revoke unique_ptr's ownership of an object by moving to a different smart pointer, or using the release member function. This breaks the association between the object and the unique_ptr and unique_ptr will no longer clean up the object.
1 The default deleter will use either delete or delete [], depending on whether the target has array type. But unique_ptr is a template and its deleter can be customized, for example the cleanup operation for a FILE* can be chosen to be a call to fclose.
This capability can be used to schedule an arbitrary cleanup action to take place when the unique_ptr goes out of scope. RAII is used for keeping locks, closing files, and so forth -- clearly there would be major problems if the cleanup action were performed early just because the compiler didn't see any future usage of the smart pointer. Luckily the C++ object lifetime rules are completely deterministic (even the order of destruction for multiple automatic variables in the same scope is well defined), and you can count on the smart pointer cleaning up its owned object exactly when the smart pointer is itself destroyed.
std::unique_ptr is RAII, as the creation of the object also initializes it.
Are you guaranteed that the object it points to won't be deleted until the unique_ptr goes out of scope [even if you're not using the unique_ptr]?
If you make a few assumptions:
You don't move the unique_ptr (that would cause the newly moved to location to be the one that will delete
You don't delete the pointer yourself or add it to another control structure.
Or put more succinctly, yes it will live that long.
It is an application of RAII, indeed.
But you are not granted that the object it points to is not deleted by someone else before the unique_ptr goes out of scope.
E.g.
int* p = new int;
int* cp = p;
std::unique_ptr<int> up(p);
delete cp;
will give undefined behavior.
std::unique_ptr can be used for RAII, but doesn't prevent you from doing something like this:
#include <memory>
class Foo{};
int main()
{
Foo* pFoo = new Foo;
std::unique_ptr<Foo> upFoo(pFoo);
delete pFoo; // WRONG, double deletion when upFoo's destructor is called
}
Usually, the best way to use smart pointers is to pass the raw pointer as their constructor or make-like function, such as
#include <memory>
class Foo{};
int main()
{
std::unique_ptr<Foo> upFoo(new Foo); // or make_unique in C++14
}
I have read from the Qt documentations about QPointer, QSharedPointer and QWeakPointer classes. It says:
QPointer is a template class that provides guarded pointers to Qt objects and behaves like a normal C++ pointer except that it is automatically set to 0 when the referenced object is destroyed and no "dangling pointers" are produced.
QSharedPointer class holds a strong reference to a shared pointer.
QWeakPointer class holds a weak reference to a shared pointer.
My questions is "What is the difference between these classes?". i.e what is the difference between a pointer to an object and a reference to a pointer? Are they all pointers to objects with different mechanisms and behaviors?
QPointer:
QPointer can only point to QObject instances. It will be automatically set to nullptr if the pointed to object is destroyed. It is a weak pointer specialized for QObject.
Consider this fragment:
QObject *obj = new QObject;
QPointer<QObject> pObj(obj);
delete obj;
Q_ASSERT(pObj.isNull()); // pObj will be nullptr now
QSharedPointer
A reference-counted pointer. The actual object will only be deleted, when all shared pointers are destroyed. Equivalent to std::shared_ptr.
int *pI = new int;
QSharedPointer<int> pI1(pI);
QSharedPointer<int> pI2 = pI1;
pI1.clear();
// pI2 is still pointing to pI, so it is not deleted
pI2.clear();
// No shared pointers anymore, pI is deleted
Note that as long as there is a shared pointer, the object is not deleted!
QWeakPointer:
Can hold a weak reference to a shared pointer. It will not prevent the object from being destroyed, and is simply reset. Equivalent to std::weak_ptr, where lock is equivalent to toStrongRef.
int *pI = new int;
QSharedPointer<int> pI1(pI);
QWeakPointer<int> pI2 = pI1;
pI1.clear();
// No shared pointers anymore, pI is deleted
//
// To use the shared pointer, we must "lock" it for use:
QSharedPointer<int> pI2_locked = pI2.toStrongRef();
Q_ASSERT(pI2_locked.isNull());
This can be used if you need access to an object that is controlled by another module.
To use a weak pointer, you must convert it to a QSharedPointer. You should never base a decision on the weak pointer being valid. You can only use data() or isNull() to determine that the pointer is null.
Generally, to use a weak pointer, you must convert it to a shared pointer since such an operation ensures that the object will survive for as long as you are using it. This is equivalent to "locking" the object for access and is the only correct way of using the object pointed to by a weak pointer.
QScopedPointer:
This is just a helper class that will delete the referenced object when the pointer goes out of scope. Thus, binds a dynamically allocated object to a variable scope.
You can use this for RAII semantics for locals, e.g.:
MyClass *foo() {
QScopedPointer<MyClass> myItem(new MyClass);
// Some logic
if (some condition) {
return nullptr; // myItem will be deleted here
}
return myItem.take(); // Release item from scoped pointer and return it
}
The item will also be deleted in case of an exception
Another use case can be member variables of an object. Then you don't need to write a destructor for those:
class MyClass {
public:
MyClass() : myPtr(new int) {}
private:
QScopedPointer<int> myPtr; // Will be deleted automatically when containing object is deleted
}
QSharedPointer : std::shared_ptr
QWeakPointer : std::weak_ptr
QScopedPointer : std::unique_ptr
QPointer : no STL equivalent. Nulled when the QObject destructs.
I have a std::vector of unique_ptrs and I'm happy to have them manage the life cycle of those objects.
However I require storing other pointers to those objects for convenience. I know that once unique_ptr removes something, those other pointers will dangle. But I'm more concerned about the validity of those pointers before and after unique_ptr gets them.
I do not always create via new within the unique_ptr itself, for example I might pass new Something as a function parameter in which case the unique_ptr is using move on that pointer into itself inside the function.
But I might also new Something before I pass it into a function that then assigned it a unique_ptr.
Once an object is assigned to a unique_ptr I can get a pointer to it via get(). But can I always assume that this get() pointer points to the same place as the pointer initially obtained via new if the original pointer was created before the assignment to a unique_ptr ?
My assumption is Yes, and that even if the vector resizes and reallocates, the unique_ptr as well as any other pointers to the objects in memory remain the same.
Yes, a std::unique_ptr<T> holds a pointer to T, and it will not alter the value between initialization and later retrieval with get()
A common use of a unique_ptr is to assign one "parent" object ownership of a dynamically-allocated "subobject", in a similiar same way as:
struct A
{
B b;
}
int main()
{
A a = ...;
B* p = &a.b;
}
In the above b is a true subobject of A.
Compare this to:
struct A
{
unique_ptr<B> b = new B(...);
}
int main()
{
A a = ...;
B* p = a.b.get();
}
In the above A and (*b) have a similar relationship to the first example, except here the B object is allocated on the heap. In both cases the destructor of A will destroy the "subobject". This "on heap" subobject structure may be preferable in some cases, for example because B is a polymorphic base type, or to make B an optional/nullable subobject of A.
The advantage of using unique_ptr over a raw pointer to manage this ownership relationship is that it will automatically destroy it in As destructor, and it will automatically move construct and move assign it as part of A.
As usual, in both cases, you must be careful that the lifetime of any raw pointers to the subobject are enclosed by the lifetime of the owning object.
Yes, you are correct, because unique_ptr does not copy the object; therefore, it has to point to the same address. However, once you give a pointer to a unique_ptr to own, you should not use that raw pointer any more, because the unique_ptr could be destroyed and deallocate the memory, and turn your raw pointer into a dangling pointer. Perhaps shared_ptr would be better for your situation.
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.