Idiom for exception safety relating to constructor parameters - c++

I've been looking at some code I'm working on, and we have the equivalent of this:
AutoPtr<A> x;
...
/// x gets initialized
...
B* y = new B(x.Detach());
Where AutoPtr is our version of auto_ptr, and Detach() returns the owned pointer and resets itself. Also, B() takes ownership of x.
Now, I realized that this will leak x if new throws an std::bad_alloc, so I changed the code to this:
AutoPtr<A> x;
...
/// x gets initialized
...
B* y = new B(x.Get());
x.Detach();
But then I realized that if B() 'owns' the pointer, and an exception happens during its construction, it should take care of deleting the parameter itself (or should it?), so the x will get deleted twice, once by B(), and once by x's destructor.
Now, is there a C++ idiom that gets around this problem, for example, making code that calls constructors responsible for cleaning up parameters? Most code I've seen doesn't seem to do that...

The obvious solution seems to be to pass a temporary AutoPtr<A> to the constructor of B:
AutoPtr<B> y(new B(AutoPtr<A>(x));
(this also adds resource control for the B* returned from new B()).
B's constructor would just call x.Detach() to initialize whatever it needs to initialize with the A*. If an exception occurs at any point, the AutoPtr<A> will release the object.
If you want to retain the A object managed by x in case of an exception, you can pass a AutoPtr<A>& to the constructor of B instead.

...it should take care of deleting the parameter itself (or should it?)
No, it should not.
B doesn't exist until the constructor completes, and if it doesn't exist it shouldn't claim ownership of anything (to a point; if the constructor itself did something, that needs to be safe as well).
The C++ idiom is to not use raw pointers for ownership (including for y)! B should accept the AutoPtr as an argument so the caller can give up ownership this way. This is the goal of std::unique_ptr and std::move:
std::unique_ptr<A> x;
std::unique_ptr<B> y(new B(std::move(x)));
Also note that really new should not be used like this as well; instead use the make_* utilities:
auto y = std::make_unique<B>(std::move(x));
But this is missing currently as oversight.

Something like this, may be:
B* y = new B();
y->Attach(x.Detach());
or
B* y = new B();
(*y) = x;

Related

Why assigning a reference to a non-reference will change its dynamic behavior

I have the following codes to dynamically allocate a class object in a function call:
#include <iostream>
class A
{
public:
A(){std::cout<<"Constructing..."<<std::endl;}
~A(){std::cout<<"Deconstructing..."<<std::endl;}
};
A & f()
{
std::cout<<"Calling f()"<<std::endl;
A * pa = new A();
std::cout<<"End calling f()"<<std::endl;
return *pa;
}
int main()
{
A & b = f();
}
The output are:
Calling f()
Constructing...
End calling f()
which means that the class object was never deleted.
However, if I change the line in main to:
A b = f();
the outputs are:
Calling f()
Constructing...
End calling f()
Deconstructing...
which means the class object was deleted automatically.
Why that assigning a reference to a non-reference will change its dynamic behavior?
There's no change to the dynamic object created by new. That's not destroyed in either case, since it can only be destroyed by explicit use of delete.
In the second case, you create a second object b by copying the dynamic object. Being automatic, that is destroyed when it goes out of scope, so you see a Deconstructing... message from that.
Since it was initialised by a copy constructor, not the default constructor, you don't see a corresponding Constructing... message. You could add a copy constructor to see that:
A(A const &){std::cout<<"Copying..."<<std::endl;}
giving the output
Calling f()
Constructing...
End calling f()
Copying...
Deconstructing...
In general, always use smart pointers and other RAII types to manage dynamic resources, to avoid memory leaks and other lifetime confusion issues.
In the case of
A & b = f();
b refers to the object created on the heap.
In the case of
A b = f();
b creates a copy (possible move) of the data on the heap. This one is destructed when the function exits (when b goes out of scope).
The object on the heap is left alone, in both cases.
To explore this further, the addition of the copy constructor would help A(A const&) and then printed a message, or even making it private and noting the compilation errors aid in marking the copies and their locations.
Note: when you new an object in a function and then don't destroy it, or don't move the pointer to some other owner, you will leak memory. Favour library utilities like unique_ptr or share_ptr to manage the resource (RAII).
When you declare a value type, it is constructed on the stack and the compiler takes care of calling its destructor when it goes out of scope. However, when you create the instance on the heap by calling new, the compiler can't know when the instance is not needed any more and therefor it's up to the programmer to indirectly call its destructor by using delete. The fact that you have a reference to the object on the heap doesn't provide the compiler with any knowledge of when the object has to be destroyed.

handling failing constructors

I am reading failing constructors from C++ FAQ and don't understand the following code.
void f()
{
X x; ← if X::X() throws, the memory for x itself will not leak
Y* p = new Y(); ← if Y::Y() throws, the memory for *p itself will not leak
}
How is it possible that the memory pointed to by p will not leak if the constructor throws? I assumed the sequence is as follows.
Memory is allocated for object Y.
Y's constructor is called.
Y's constructor throws and memory pointed to by p leaks.
If Y's constructor throws, then the stack is unwound, including deleting the memory allocated for Y.
The problems arise primarily when/if you have more than one object to deal with. For example:
void f() {
X *x = new X();
Y *y = new Y();
}
Now, if the new X() part succeeds, but the new Y() part fails, the memory allocated for y will be deleted, but x will not be destroyed, and its memory will be leaked. You can work around this problem with try blocks, if you really insist:
try {
X *x = new X();
Y * y = new Y();
}
catch (y_construction_failed) {
delete x;
}
The big problem with this is that you have to nest the try blocks if you have more than two items, so if you need, say, half a dozen local variables, it's going to be deeply nested and excruciatingly ugly.
You will run into a similar problem having a function void f(X*, Y*) and calling f(new X(), new Y()). If one of the new calls succeeds and the other fails you have a memory leak. To resolve it you might create additional functions 'X* make_X()' and 'Y* make_Y()' returning pointers. Now, f(make_X(), make_Y()) is safe. (And after going that far, you might use smart pointers)
It's important to notice that even though the object is deleted, its destructor is not called in this case.
This makes sense, since an exception during construction indicates that the object was never fully constructed (ie. its class invariants have not been established), so calling the destructor could be dangerous.
The downside of this is that if the constructor performs actions that require cleanup which would normally be performed by the destructor, it is now the constructor's responsibility to perform this cleanup in case of exceptions. Take the following example:
class C {
private:
int* p1;
int* p2;
public:
C() : p1(new int()), p2(new int()) {}
~C() { delete p1; delete p2; }
};
If the allocation p2 throws, the memory already allocated for p1 will leak. It is your responsibility as a programmer to write constructors in a way that this cannot happen.
The easiest way to achieve this is by delegating the resource management responsibilities to a RAII container class like unique_ptr. That way, no class is responsible for managing more than one resource and scenarios like the one outlined above can no longer occur.

No suitable constructor exists to convert from "dumb pointer" to "smart pointer"

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);
...
}

C++: making shallow copy of an object a) syntax b) do i need to delete it

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.

Lifetime management of encapsulated objects

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.