I am trying to understand the preferred approach for a class to handle the validity of (reference to) the object of another class.
In here, C has a vector that stores references of D objects. If D and C are a part of the library, how should C handle the case where a D object goes out of scope in the caller?
A couple approaches that I have in mind though not sure of the feasibility:
Dknows about what_liststores and as soon as the saidDgoes out of scope,~D()runs which removes itself from_list._liststoresweak_ptrinstead of a raw and upon any access toD, you invokeweak_ptr::lock()prior to accessing, though this will require the instantiation of ashared_ptrwhich seems to be not so common in production?
struct D
{
~D()
{
printf ("~D()\n");
}
};
class C
{
vector<D*> _list;
public:
void add(D* dObject)
{
_list.push_back(dObject);
printf ("Adding D => size = %ld\n", _list.size());
}
~C()
{
printf ("~C()\n");
}
};
int main()
{
C c1;
{
D d1;
c1.add(&d1);
}
/**
_list[0] is garbage now. How to avoid accessing it i.e
C being aware to not access it?
*/
printf ("----out of scope---\n");
D d2;
c1.add(&d2);
}
Essentially, the original question is asking: "how do I know when a local variable goes out of scope?"
The answer is: when its destructor is called.
For the code in your question, you could have
~D()to remove itself fromc1. This is awkward, and the discussion beneath the question brings upstd::shared_ptr, but the code in the example uses a local variable. You can't usestd::shared_ptron a local variable, only on a heap variable. This is not made clear in the discussion.Here are two references to questions specifically related to shared_ptr and local variables:
Create shared_ptr to stack object
and
Set shared_ptr to point existing object
A better solution to your problem is to not use a local variable, but a heap variable.
The difference between local and heap variables seems to be causing some confusion.
C++ has several storage classes for variables:
C++ has some tricks with
newanddeletewhere you can use a custom heap, which is memory you're managing yourself, but that memory will have been allocated from the general heap, or possibly exist inside other variables.Here are three different examples:
A local variable:
When this function exits, the stack frame that contains d1 goes away, and the variable ceases to exist.
~D()will get called, and you could remove d1 from c1 if you added a mechanism to do this, like makingd1hold a pointer toc1, etc., which is awkward, but possible.std::shared_ptrwill not help with a local variable.A heap variable allocated with new:
When this function exits, the
Dvariable thatd1ppoints to still exists. It will continue exist until it is explicitly deleted. In this context, thec1variable "owns" this pointer, and it responsible for deleting it when it has finished using it.This is the case where adding a smart pointer can simplify reference management, as in:
A heap variable and shared_ptr created via make_shared:
This example creates a
Dvariable on the heap, and creates a localshared_ptrholding a reference to thatDvariable, via a small counter object, which is also on the heap. When theshared_ptris passed to theC::addmethod, the reference count in the counter object is incremented. When theshared_ptrgoes out of scope, the reference count in the counter object is decremented. Theshared_ptrin thec1object now holds the only reference to thatshared_ptr, and when thec1object is destroyed, theshared_ptrit contains will be destroyed, releasing its reference - if the count goes to zero, the object it points to will also be destroyed.Besides this automatic destruction, another advantage of this approach is that you can get references to this
Dvariable fromc1and use them elsewhere, and these references (and theDvariable itself) can outlivec1.The
Cclass has to be modified for this case, e.g.and
Here's a reference to how shared pointers work:
How do shared pointers work?
and some documentation on make_shared:
https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared