What is the best approach to encapsulate objects and manage their lifetime? Example: I have a class A, that contains an object of type B and is solely responsible for it.
Solution 1, clone b object to ensure that only A is able to clean it up.
class A
{
B *b;
public:
A(B &b)
{
this->b = b.clone();
}
~A()
{
delete b; // safe
}
};
Solution 2, directly use the passed object, we risk a potential double free here.
class A
{
B *b;
public:
A(B *b)
{
this->b = b;
}
~A()
{
delete b; // unsafe
}
};
In my actual case, solution #2 would fit best. However I wonder if this is considered bad code because someone might not know about the behavior of A, even if it's documented. I can think of these scenarios:
B *myB = new B();
A *myA = new A(myB);
delete myB; // myA contains a wild pointer now
Or,
B *myB = new B();
A *firstA = new A(myB);
A *secondA = new A(myB); // bug! double assignment
delete firstA; // deletes myB, secondA contains a wild pointer now
delete secondA; // deletes myB again, double free
Can I just ignore these issues if I properly document the behavior of A? Is it enough to declare the responsibility and leave it up to the others to read the docs? How is this managed in your codebase?
I never delete anything myself unless I really have to. That leads to errors.
Smart pointers are your friend. std::auto_ptr<> is your friend when one object owns another and is responsible for deleting it when going out of scope. boost::shared_ptr<> (or, now, std::tr1::shared_ptr<>) is your friend when there's potentially more than one object attached to another object, and you want the object deleted when there's no more references to it.
So, either use your solution 1 with auto_ptr, or your solution 2 with shared_ptr.
You should define your object so that the ownership semantics are, as much as possible, defined by the interface. As David Thornley pointed out, std::auto_ptr is the smart pointer of choice to indicate transfer of ownership. Define your class like so:
class A
{
std::auto_ptr<B> b;
public:
A(std::auto_ptr<B> b)
{
this->b = b;
}
// Don't need to define this for this scenario
//~A()
//{
// delete b; // safe
//}
};
Since the contract of std::auto_ptr is that assignment = transfer of ownership, your constructor now states implicitly that an A object has ownership of the pointer to B it's passed. In fact, if a client tries to do something with a std::auto_ptr<B> that they used to construct an A after the construction, the operation will fail, as the pointer they hold will be invalid.
If you are writing code that someone else will be using later, these issues must be addressed. In this case I would go for simple reference counting (maybe with smart pointers). Consider the following example:
When an instance of the encapsulating class is assigned an object B, it calls a method to increase object's B reference counter. When the encapsulating class is destroyed, it doesn't delete B, but instead calls a method do decrease reference count. When the counter reaches zero, object B is destroyed (or destroys itself for that matter). This way multiple instances of encapsulating class can work with a single instance of object B.
More on the subject: Reference Counting.
If your object is solely responsible for the passed object then deleting it should be safe. If it is not safe than the assertion that you are solely responsible is false. So which is it? If you're interface is documented that you WILL delete the inbound object, then it is the caller responsibility to make sure you receive an object that must be deleted by you.
If you're cloning A, and both A1 and A2 retain references to B, then B's lifetime is not being controlled entirely by A. It's being shared among the various A. Cloning B ensures a one-to-one relationship between As and Bs, which will be easy to ensure lifetime consistency.
If cloning B is not an option, then you need to discard the concept that A is responsible for B's lifetime. Either another object will need to manage the various B, or you'll need to implement a method like reference counting.
For reference, when I think of the term 'Clone', it implies a deep copy, which would clone B as well. I'd expect the two As to be completely detached from each other after a clone.
I don't clone things unnecessarily or "just to be safe".
Instead I know whose responsibility it is to delete something: either via documentation, or by smart pointers ... for example, if I have a create function which instantiates something and returns a pointer to it and doesn't delete it, so that it's unclear where and by whome that thing is ever supposed to be deleted, then instead of create's returning a naked pointer I might define create's return type as returning the pointer contained within some kind of smart pointer.
Related
What is the canonical way to deal with shared pointers in C++ when there is a clear case to argue that "one, unique object owns the pointer"?
For example, if a shared_ptr is a member of a particular class, which is responsible for initializing the pointer, then it could be argued that this class should also have the final say on when the pointer is deleted.
In other words, it may be the case that when the owning class goes out of scope (or is itself delete'd that any remaining references to the pointer no longer make sense. This may be due to related variables which were members of the destroyed class.
Here is a sketch of an example
class Owner
{
Owner()
{
p.reset(malloc_object(arguments), free_object);
}
std::shared_ptr<type> get() { return p; }
// seems strange because now something somewhere
// else in the code can hold up the deletion of p
// unless a manual destructor is written
~Owner()
{
p.reset(nullptr); // arduous
}
std::shared_ptr<type> p;
int a, b, c; // some member variables which are logically attached to p
// such that neither a, b, c or p make sense without each other
}
One cannot use a unique_ptr as this would not permit the pointer to be returned by the get function, unless a raw pointer is returned. (Is this is an acceptable solution?)
A unique_ptr in combination with returning weak_ptr from the get function might make sense. But this is not valid C++. weak_ptr is used in conjunction with shared_ptr.
A shared_ptr with the get function returning weak_ptr is better than a raw pointer becuase in order to use the weak pointer, it has to be converted to a shared pointer. This will fail if the reference count is already zero and the object has been deleted.
However using a shared_ptr defeats the point, since ideally a unique_ptr would be chosen because there can then only be one thing which "owns" the pointed to data.
I hope the question is clear enough, it was quite difficult to explain since I can't copy the code I am working with.
It is ok to return the shared_ptr there, what will happen is that the pointer will still be held somewhere outside the Owner class. Since your doing p.reset(nullptr); at the destructor, whoever was holding that shared_ptr will now be holding a pointer to null.
Using weak_ptr with shared_ptr is also a good solution, the problem is the same which is the fact that the best class to represent p is unique_ptr as you described.
The path I would choose is to hold a unique_ptr which seems more adequate and to implement the get() function like this:
type* get() { return p.get(); }
The behaviour is the same and the code is clearer since having p as unique_ptr will give clarity on how it should be used.
My following question is on memory management. I have for example an int variable not allocated dynamically in a class, let's say invar1. And I'm passing the memory address of this int to another classes constructor. That class does this:
class ex1{
ex1(int* p_intvar1)
{
ptoint = p_intvar1;
}
int* ptoint;
};
Should I delete ptoint? Because it has the address of an undynamically allocated int, I thought I don't need to delete it.
And again I declare an object to a class with new operator:
objtoclass = new ex1();
And I pass this to another class:
class ex2{
ex2(ex1* p_obj)
{
obj = p_obj;
}
ex1* obj;
};
Should I delete obj when I'm already deleting objtoclass?
Thanks!
Because it has the address of an undynamically allocated int I thought I don't need to delete it.
Correct.
Should I delete obj when I'm already deleting objtoclass?
No.
Recall that you're not actually deleting pointers; you're using pointers to delete the thing they point to. As such, if you wrote both delete obj and delete objtoclass, because both pointers point to the same object, you'd be deleting that object twice.
I would caution you that this is a very easy mistake to make with your ex2 class, in which the ownership semantics of that pointed-to object are not entirely clear. You might consider using a smart pointer implementation to remove risk.
just an appendix to the other answers
You can get rid of raw pointers and forget about memory management with the help of smart pointers (shared_ptr, unique_ptr).
The smart pointer is responsible for releasing the memory when it goes out of scope.
Here is an example:
#include <iostream>
#include <memory>
class ex1{
public:
ex1(std::shared_ptr<int> p_intvar1)
{
ptoint = p_intvar1;
std::cout << __func__ << std::endl;
}
~ex1()
{
std::cout << __func__ << std::endl;
}
private:
std::shared_ptr<int> ptoint;
};
int main()
{
std::shared_ptr<int> pi(new int(42));
std::shared_ptr<ex1> objtoclass(new ex1(pi));
/*
* when the main function returns, these smart pointers will go
* go out of scope and delete the dynamically allocated memory
*/
return 0;
}
Output:
ex1
~ex1
Should I delete obj when I'm already deleting objtoclass?
Well you could but mind that deleting the same object twice is undefined behaviour and should be avoided. This can happen for example if you have two pointers for example pointing at same object, and you delete the original object using one pointer - then you should not delete that memory using another pointer also. In your situation you might as well end up with two pointers pointing to the same object.
In general, to build a class which manages memory internally (like you do seemingly), isn't trivial and you have to account for things like rule of three, etc.
Regarding that one should delete dynamically allocated memory you are right. You should not delete memory if it was not allocated dynamically.
PS. In order to avoid complications like above you can use smart pointers.
You don't currently delete this int, or show where it's allocated. If neither object is supposed to own its parameter, I'd write
struct ex1 {
ex1(int &i_) : i(i_) {}
int &i; // reference implies no ownership
};
struct ex2 {
ex2(ex1 &e_) : e(e_) {}
ex1 &e; // reference implies no ownership
};
int i = 42;
ex1 a(i);
ex2 b(a);
If either argument is supposed to be owned by the new object, pass it as a unique_ptr. If either argument is supposed to be shared, use shared_ptr. I'd generally prefer any of these (reference or smart pointer) to raw pointers, because they give more information about your intentions.
In general, to make these decisions,
Should I delete ptoint?
is the wrong question. First consider things at a slightly higher level:
what does this int represent in your program?
who, if anyone, owns it?
how long is it supposed to live, compared to these classes that use it?
and then see how the answer falls out naturally for these examples:
this int is an I/O mapped control register.
In this case it wasn't created with new (it exists outside your whole program), and therefore you certainly shouldn't delete it. It should probably also be marked volatile, but that doesn't affect lifetime.
Maybe something outside your class mapped the address and should also unmap it, which is loosely analogous to (de)allocating it, or maybe it's simply a well-known address.
this int is a global logging level.
In this case it presumably has either static lifetime, in which case no-one owns it, it was not explicitly allocated and therefore should not be explicitly de-allocated
or, it's owned by a logger object/singleton/mock/whatever, and that object is responsible for deallocating it if necessary
this int is being explicitly given to your object to own
In this case, it's good practice to make that obvious, eg.
ex1::ex1(std::unique_ptr<int> &&p) : m_p(std::move(p)) {}
Note that making your local data member a unique_ptr or similar, also takes care of the lifetime automatically with no effort on your part.
this int is being given to your object to use, but other objects may also be using it, and it isn't obvious which order they will finish in.
Use a shared_ptr<int> instead of unique_ptr to describe this relationship. Again, the smart pointer will manage the lifetime for you.
In general, if you can encode the ownership and lifetime information in the type, you don't need to remember where to manually allocate and deallocate things. This is much clearer and safer.
If you can't encode that information in the type, you can at least be clear about your intentions: the fact that you ask about deallocation without mentioning lifetime or ownership, suggests you're working at the wrong level of abstraction.
Because it has the address of an undynamically allocated int, I
thought I don't need to delete it.
That is correct. Simply do not delete it.
The second part of your question was about dynamically allocated memory. Here you have to think a little more and make some decisions.
Lets say that your class called ex1 receives a raw pointer in its constructor for a memory that was dynamically allocated outside the class.
You, as the designer of the class, have to decide if this constructor "takes the ownership" of this pointer or not. If it does, then ex1 is responsible for deleting its memory and you should do it probably on the class destructor:
class ex1 {
public:
/**
* Warning: This constructor takes the ownership of p_intvar1,
* which means you must not delete it somewhere else.
*/
ex1(int* p_intvar1)
{
ptoint = p_intvar1;
}
~ex1()
{
delete ptoint;
}
int* ptoint;
};
However, this is generally a bad design decision. You have to root for the user of this class read the commentary on the constructor and remember to not delete the memory allocated somewhere outside class ex1.
A method (or a constructor) that receives a pointer and takes its ownership is called "sink".
Someone would use this class like:
int* myInteger = new int(1);
ex1 obj(myInteger); // sink: obj takes the ownership of myInteger
// never delete myInteger outside ex1
Another approach is to say your class ex1 does not take the ownership, and whoever allocates memory for that pointer is the responsible for deleting it. Class ex1 must not delete anything on its destructor, and it should be used like this:
int* myInteger = new int(1);
ex1 obj(myInteger);
// use obj here
delete myInteger; // remeber to delete myInteger
Again, the user of your class must read some documentation in order to know that he is the responsible for deleting the stuff.
You have to choose between these two design decisions if you do not use modern C++.
In modern C++ (C++ 11 and 14) you can make things explicit in the code (i.e., do not have to rely only on code documentation).
First, in modern C++ you avoid using raw pointers. You have to choose between two kinds of "smart pointers": unique_ptr or shared_ptr. The difference between them is about ownership.
As their names say, an unique pointer is owned by only one guy, while a shared pointer can be owned by one or more (the ownership is shared).
An unique pointer (std::unique_ptr) cannot be copied, only "moved" from one place to another. If a class has an unique pointer as attribute, it is explicit that this class has the ownership of that pointer. If a method receives an unique pointer as copy, it is explicit that it is a "sink" method (takes the ownership of the pointer).
Your class ex1 could be written like this:
class ex1 {
public:
ex1(std::unique_ptr<int> p_intvar1)
{
ptoint = std::move(p_intvar1);
}
std::unique_ptr<int> ptoint;
};
The user of this class should use it like:
auto myInteger = std::make_unique<int>(1);
ex1 obj(std::move(myInteger)); // sink
// here, myInteger is nullptr (it was moved to ex1 constructor)
If you forget to do "std::move" in the code above, the compiler will generate an error telling you that unique_ptr is not copyable.
Also note that you never have to delete memory explicitly. Smart pointers handle that for you.
If my class has a pointer of some sort that can be set by the class clients, how should I deal with deletion?
Example:
class A {
};
class B {
public:
void setA(A* a) {
this->a = a;
}
private:
A* a;
};
How should be the destructor of the class B? Should it delete a? As I see, there are two way a user can set this pointer:
... // Assume B object b being created elsewhere
A aObj;
A* aPtr = new A();
b.setA(&aObj); // It is not OK to use delete, and class member will
// point to invalid memory location once aObj goes out
// of scope
b.setA(aPtr); // Using new will make the pointer available even after
// this block of code
...
So what is the right way of deleting b? Should I always perform a new in my set method?
How should be the destructor of the class B? Should it delete a?
You, the author of the class, decides of its semantics. Don't think in terms of pointers, references, and deletes. Think in terms of design: what's the relation between A and B? What does B needs a A for?
Two common types of relation are delegation and composition. Delegation would mean that client code uses the setA member to have the instance aware of some other B instance that it may use for further uses. Composition would mean that the setA member is used to initialize an internal part of the instance.
One possible implementation of delegation is using a member pointer. I'd recommend passing a reference to setA to assign to that pointer; it sidesteps the issue of checking for 0 and makes it obvious to client code that there is no ownership issue to deal with. This is compatible with polymorphic types.
One possible implementation of composition is using a A member, and passing by reference to const or by value to assign to it. Another is to use a smart pointer, especially if A is meant to be used polymorphically. Passing by smart pointer is the simplest thing to do -- but you'll have to check for 0 and/or document the cast.
No matter what you decide to use (which doesn't have to be in this list anyway), use code as a tool to achieve your purpose or design. Don't let code dictate your thoughts.
In all my example implementations you don't have to do anything special in the destructor.
You should really really not have such a class in the first place. Instead, use a resource managing container like shared_ptr or unique_ptr to hold the pointer to a dynamically allocated object.
As you can easily see, there's no way you'll manage to keep track of who's responsible for what if you randomly allocate dynamic objects all over the place. What about copying and assignment of your class? What about exceptions in the constructor? Don't do it.
I think there would normally be be 3 scenarios, see code below:
//class B doesn't own a
class B {
public:
void setA(A& a) {
m_a = a;
}
private:
A& m_a; //Only a reference , so need to worry about delete
};
//class B owns A
class B {
public:
void setA(std::auto_ptr<A>& a) {
m_a.reset(a.release());
}
private:
boost::scoped_ptr<A> m_a; //m_a got deleted when instance of B lifetime end
};
//class B shared A with someone else
class B {
public:
void setA(boost::shared_ptr<A>& a) {
m_a = a;
}
private:
boost::shared_ptr<A> m_a; //m_a got deleted when no one need this pointer anymore(reference counting reduced to 0)
};
You have a design decision to make. Who should own the object?
The B object owns the A object, and setA passes ownership to B. B's destructor should delete the A.
Some outer code owns the A object. B will not delete it, but will depend on that outer code to destroy it at the proper time.
A smart pointer tracks the references to the A object and deletes it automatically when all references are destroyed.
The third option with the smart pointer is the simplest and most reliable, but all 3 choices can be made to work. The trick is to pick one and be deliberate about it.
During your design analysis you will have to answer the following questions:
Does object A depends on the lifetime of object B, if yes then use "composition" in which case object B will create A and is responsible for deleting it before object B itself is destroyed.
If object A is independent of the lifetime of object B then use "aggregation". You supply object A to B via B's constructor or a set method. Object B does not have to worry about destroying object A but you will have to be certain that during the lifetime of B that A is in a valid state.
If A depends on object B's lifetime but you need to create A before B, then do "dependency injection". It's like aggregation in that you can pass A to B in the constructor or set method, but A is exclusively used by B in this case and no other object is using A. B deletes A before its own destruction.
From the looks of this, you are trying to create a reference to your A object within your B class.
To clean up B properly, you would have to check if A is null first. Something like...
~B()
{
if (A)
{
delete A;
A = 0;
}
}
Keep in mind this also deletes the A object outside of the class, because they're referencing the same memory. So in a case like this, you could VERY easily reference a pointer to invalid memory if you deleted the A object.
I would not use this with a local variable either btw, as you'll lose the address of it when it goes out of scope. However, a local pointer on the other hand..well, then you won't have to worry about referencing invalid memory once you've left the scope of where A was created.
struct A
{
A(int a);
};
struct B
{
B();
void b(std::shared_ptr<A> a);
};
int main()
{
A a(1);
B b;
b.b(&a);
}
So I got this error, sorry guys it's my frist time with the smart pointers!!
Error:
no suitable constructor exists to convert from "A *" to "std::tr1::shared_ptr<A>"
How do I fix this problem!?
The entire point of a smart pointer is to have ownership. That is, it's responsible for the deallocation of whatever it's pointing it. It simply doesn't make sense to try to tell it to manage something that's already being managed by a completely different system.
In your case, a is already being automatically managed, why would you want to also be managed by a smart pointer? Even if that worked, you'd just be setting yourself for deleting it twice, which is UB.
Either give it something to own, like new A(1), or change b to operate on something it doesn't own.
Others already ranted on the design error of your code, but not the real problem why the code doesn't even compile. shared_ptr has a constructor that accepts a raw pointer, but it is marked as explicit, which means you have to explicitly write out that you want to construct a shared_ptr instance. What your function call tries, is to do that construction implicitly, which isn't allowed because of the explicit keyword.
The following will compile but give undefined behaviour because the shared_ptr will (try to) delete an object which resides on the stack and is as such not deleteable:
b.b(shared_ptr<A>(&a)); // explicit construction
A special trait of shared_ptr is that you can pass the constructor a deleter, which will be called when the owned pointer should be deleted. You can just write and use a "noop" deleter, which does just nothing; the following will not invoke undefined behaviour and will not try to delete the stack variable:
// outside of main
void noop_deleter(A*){/*do nothing*/}
// call...
b.b(shared_ptr<A>(&a, noop_deleter));
And there actually is a use for this, if you have a library API that absolutely wants a shared_ptr but you want to call it with a stack variable. The design of that API is another thing though...
std::tr1::shared_ptr has one constructor that allows to pass down a given raw pointer. So if you had a pointer to A, you would do something like:
std::shared_ptr (pMyA)
but in your case, your pointer to A points to an automatic variable NOT to a dynamically allocated memory resource that can be deleted after usage.
Something like this would be a better use case:
class B
{
void b (shared_ptr <A> pA) {}
}
int main ()
{
shared_ptr<A> pA (new A);
B b;
b.b (pA);
...
}
I have a class MyClassA. In its constructur, I am passing the pointer to instance of class B. I have some very basic questions related to this.
(1) First thing , is the following code correct? ( the code that makes a shallow copy and the code in methodA())
MyClassA::MyClassA(B *b){
this.b = b;
}
void MyClassA::methodA(){
int i;
i = b.getFooValue();
// Should I rather be using the arrow operator here??
// i = b->getFooValue()
}
(2) I am guessing I don't need to worry about deleting memory for MyClassA.b in the destructor ~MyClassA() as it is not allocated. Am I right?
thanks
Update: Thank you all for your answers! MyclassA is only interested in accessing the methods of class B. It is not taking ownership of B.
You need the arrow operator since b is a pointer.
Yes, unless the user of MyClassA expects to take the ownership of b. (You can't even be sure if b is a stack variable where delete-ing it will may the code crash.)
Why don't you use a smart pointer, or even simpler, a reference?
First thing , is the following code
correct? ( the code that makes a
shallow copy and the code in
methodA())
The answer depends upon who owns the responsibility of the B object's memory. If MyClassA is supposed just to store the pointer of A without holding the responsibility to delete it then it is fine. Otherwise, you need to do the deep copy.
I am guessing I don't need to worry
about deleting memory for MyClassA.b
in the destructor ~MyClassA() as it is
not allocated. Am I right?
Again depends on how memory for B is allocated. Is it allocated on stack or heap? If from stack then you need not explicitly free it in destructor of MyClassA, otherwise you need to to delete it.
1) . It depends on the life time of the pointer to B.
Make sure the when you call b->getFooValue(); b should be a valid pointer.
I will suggest use of initilization list and if you are only reading the value of the B object though it pointer then make it pointer to constant data.
MyClassA::MyClassA(const B *bObj) : b(bObj)
{}
2). As long as B is on the stack on need to delete it and if it is allocated to heap then it must be deleted by it the owner else you will have memory leak.
You can use smart pointer to get rid of the problem.
MyClassA::MyClassA(B *b){
this.b = b;
}
should be:
MyClassA::MyClassA(B *b){
this->b = b;
}
because this is treated as a pointer.
1)
this.b = b;
Here you pass a pointer to an instance of B. As Mac notes, this should be:
this->b = b;
b.getFooValue();
This should be b->getFooValue(), because MyClassA::b is a pointer to B.
2) This depends of how you define what MyClassA::b is. If you specify (in code comments) that MyClassA takes over ownership over the B instance passed in MyClassA's constructor, then you'll need to delete b in MyClassA's destructor. If you specify that it only keeps a reference to b, without taking over the ownership, then you don't have to.
PS. Regrettably, in your example there is no way to make ownership explicit other than in code documentation.