Throwing exception from a function parameter - c++

Does the code below produce a memory leak?
#include <utility>
#include <stdexcept>
struct A {};
struct B {
B() {
throw std::runtime_error("");
}
};
template <class T>
class MyPtr {
public:
MyPtr(T* p) : m_p(p) {}
MyPtr(MyPtr&& other) : m_p(other.m_p) {
other.m_p = nullptr;
}
~MyPtr() {
delete m_p;
}
private:
T* m_p;
};
class Foo {
public:
Foo(MyPtr<A> a, MyPtr<B> b) : m_a(std::move(a)), m_b(std::move(b)) {}
private:
MyPtr<A> m_a;
MyPtr<B> m_b;
};
int main() {
try {
Foo foo(new A(), new B());
}
catch (const std::exception&) {
}
return 0;
}
Is there a difference between
Foo foo(new A(), new B());
and
Foo foo(MyPtr(new A()), MyPtr(new B()));
?

The evaluation order is based on sequenced-before and sequenced-after in modern C++ versions. This means, the following will happen:
in any non-overlapping order: new A(), new B() - memory is allocated for A and B and constructors are run (these cannot be interleaved)
since B has a ctor, this ctor is run (sequenced-after allocation)
B's ctor throws
since B's ctor didn't complete, the memory allocated by new for constructing B will be freed, without calling dtor.
Note that the call to Foo's ctor would be sequenced-after the above, so it won't be reached.
Thus, B is not leaked. However, function parameters can be sequenced in any non-overlapping way, so A might or might not be leaked. This might, in theory, change from run to run.
If you do: Foo foo(MyPtr(new A()), MyPtr(new B()));, then you immediately encapsulate the pointers to smart pointers after new, so it won't leak.
Also, it's worth mentioning, while the memory for B is deallocated, any memory that's allocated in B's ctor and not deallocated till throw can still potentially leak. In this example there's no such allocation, but in actual codes it might occur. The only memory deallocated is that of the entire object being constructed.

Since C++17, no leak occurs in either case, but this interpretation hinges on the definition of initialization of a parameter. Does the initialization of a begin by evaluating new A(), or does it start after that expression has already been reduced to a pointer value? CWG2599 answers this question with the broader choice, as makes sense especially for aggregate initialization where the parameter obviously already exists (albeit only partially initialized) before all the initializer-clauses have been evaluated at all.

Related

Should I use unique_ptr to keep class' members?

I have such code:
class A
{
public:
A(void);
~A(void)
{
delete b;
delete c;
delete d;
// ...
}
private:
B* b;
C* c;
D* d;
// ...
};
//A.cpp
A(void) : b(new B()), c(new C()), d(new D()) //...
{
}
Class A takes ownership over own objects b, c, d ...
What is the best way to keep these objects? I guess, that usage of std::unique_ptr<B/C/D> type will be suitable for this way. For example, it allows to don't care about carefull writing of destructor.
it allows to don't care about carefull writing of destructor.
More than that.
Your code is not exception-safe. For example, if new D() failed by exception being thrown, delete b and delete c won't be executed and memory will leak, because destructor won't be called if constructor fails. Smart pointers can help you to avoid this kind of situation.
Holding raw pointer as members you need to implement destructor carefully, and copy constructor and assignment etc too. See What is The Rule of Three? and Rule-of-Three becomes Rule-of-Five with C++11?.
Best is to keep everything by value. If it fits*, and does not need to be hidden**. If it does not fit or needs to be hidden first preference is std::unique_ptr***, second preference (if ownership has to be shared) is std::shared_ptr. And only as a last resort (example for which I cannot even think up). You would actually have raw pointers and manage lifetime yourself, with risk of memory errors and leaks.
* - sometimes you want to be able to have parent object on stack by value and child objects are, say, large arrays which, if stored by value would overflow the stack
** - sometimes you don't want to show what child objects really are (because they are complex, say boost.fusion adapted classes. Then you would want some form of PIMPL idiom:
class.hpp
struct b;
struct A { std::unique_ptr<b> b_; A(); ~A(); }
class.cpp:
struct b { ... }
A::A() = default;
A::~A() = default;
*** - automatic management of dynamically allocated members with unique_ptr
struct A {
std::unique_ptr<b> b_;
A(...):
b_(std::make_unique<b>(...)) {}
};
I think it's worth mentioning that if you do not want to transfer ownership, you must use const std::unique_ptr. Using a non-const std:unique_ptr allows to transfer it to another std:unique_ptr.

Uncaught exception at constructor after allocating memory

I've read that awesome summary of Michael Burr regarding a constructor that throws an exception, here: Will the below code cause memory leak in c++
My question is: Is the behavior similar when an exception is thrown by a function called from constructor? i.e. in case that the exception isn't caught where it was thrown and thus it climbs up to the constructor and further to the function that called to the constructor.
I'm especially interested to know what about the member objects contained in that object's class, will their destructors be called? More specifically, in my case it's about a member of type boost::shared_ptr.
Consider the following example:
class A {
A() { throw some_exception }
};
class B {
B() { A a = new A(); }
};
class C {
boost::shared_ptr<B> p2b;
int i;
int *pint;
someclass objsomeclass;
someclass* psomeclass;
public:
C() {
objsomeclass = someclass();
psomeclass = new someclass();
pint = new int();
p2b(new B);
}
};
void foo()
{
C c();
}
main()
{
foo();
}
Will the destructor of p2a be called?
I'll appreciate if you could point me to an appropriate and reliable resource that covers this case.
Assuming you change the code so it compiles, the destructor of p2a (now p2b) will be called because it was successfully default-constructed. However, it will still hold NULL, because your attempt to reset it in the body of C::C fails.
The memory allocated by new B will be cleaned up automatically by the stack unwinding process. However, pint and psomeclass will both be leaked, because you're not using RAII for these members.
To clarify, let's step through the code:
C::C() {
objsomeclass = someclass();
psomeclass = new someclass();
pint = new int();
p2b.reset(new B);
/* in your code as posted, the call sequence is:
new B (allocate sizeof B)
-> B::B
-> new A (allocate sizeof A)
-> A::A which throws
<- new A failed, so memory is freed
<- B::B failed (initialized subobjects would be
destroyed here, but there are none)
new B failed, so memory is freed
*/
}
Note that:
all members are already default-initialized (because you didn't use the initializer list), so they all get destroyed when the body of C::C unwinds
if psomeclass and pint were smart pointers, this would release their dynamically-allocated memory. They aren't, so this is leaked.
In general, it is better style to use the initializer list and RAII.
For reference, maybe start with this (very old) article: GOTW 66

new int[size] vs std::vector

To allocate dynamic memory, I have been using vectors all this time in C++.
But recently, while reading some source code, I found the use of "new int[size]" and on some research, found that it too allocates dynamic memory.
Can anyone give me advice as to which is better? I am looking from an algorithmic and ICPC point of view?
Always prefer the standard containers. They have well-defined copying semantics, are exception safe, and release properly.
When you allocate manually, you must guarantee that the release code is executed, and as members, you must write correct copy assignment and copy constructor which does the right thing without leaking in case of exception.
Manual:
int *i = 0, *y = 0;
try {
i = new int [64];
y = new int [64];
} catch (...) {
delete [] y;
delete [] i;
}
If we want our variables to have only the scope they really need, it gets smelly:
int *i = 0, *y = 0;
try {
i = new int [64];
y = new int [64];
// code that uses i and y
int *p;
try {
p = new int [64];
// code that uses p, i, y
} catch(...) {}
delete [] p;
} catch (...) {}
delete [] y;
delete [] i;
Or just:
std::vector<int> i(64), y(64);
{
std::vector<int> p(64);
}
It is a horror to implement that for a class that has copy semantics. Copying may throw, allocation may throw, and we want transaction semantics, ideally. An example would burst this answer tho.
Ok here.
Copyable class - Manual resource management vs containers
We have this innocent looking class. As it turns out, it is pretty evil. I feel reminded of American McGee's Alice:
class Foo {
public:
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
private:
Bar *b_;
Frob *f_;
};
Leaks. Most beginner C++ programmers recognize that there's missing deletes. Add them:
class Foo {
public:
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
~Foo() { delete f_; delete b_; }
private:
Bar *b_;
Frob *f_;
};
Undefined behavior. Intermediate C++ programmers recognize that the wrong delete-operator is used. Fix this:
class Foo {
public:
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
~Foo() { delete [] f_; delete [] b_; }
private:
Bar *b_;
Frob *f_;
};
Bad design, leaks and double deletes lurk there if the class is copied. The copying itself is fine, the compiler cleanly copies the pointers for us. But the compiler won't emit code to create copies of the arrays.
Slightly more experienced C++ programmers recognize that the Rule of Three was not respected, which says that if you have explicitly written any of destructor, copy assignment or copy constructor, you probably also need to write out the others, or make them private without implementation:
class Foo {
public:
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
~Foo() { delete [] f_; delete [] b_; }
Foo (Foo const &f) : b_(new Bar[64]), f_(new Frob[64])
{
*this = f;
}
Foo& operator= (Foo const& rhs) {
std::copy (rhs.b_, rhs.b_+64, b_);
std::copy (rhs.f_, rhs.f_+64, f_);
return *this;
}
private:
Bar *b_;
Frob *f_;
};
Correct. ... Provided you can guarantee to never run out of memory and that neither Bar, nor Frob can fail on copying. Fun starts in next section.
The wonderland of writing exception safe code.
Construction
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
Q: What happens if the initialization of f_ fails?
A: All Frobs that have been constructed are destroyed. Imagine 20 Frob were constructed, the 21st will fail. Than, in LIFO order, the first 20 Frob will be correctly destroyed.
That's it. Means: You have 64 zombie Bars now. The Foos object itself never comes to life, its destructor will therefore not be called.
How to make this exception safe?
A constructor should always succeed completely or fail completely. It shouldn't be half-live or half-dead. Solution:
Foo() : b_(0), f_(0)
{
try {
b_ = new Bar[64];
f_ = new Frob[64];
} catch (std::exception &e) {
delete [] f_; // Note: it is safe to delete null-pointers -> nothing happens
delete [] b_;
throw; // don't forget to abort this object, do not let it come to life
}
}
Copying
Remember our definitions for copying:
Foo (Foo const &f) : b_(new Bar[64]), f_(new Frob[64]) {
*this = f;
}
Foo& operator= (Foo const& rhs) {
std::copy (rhs.b_, rhs.b_+64, b_);
std::copy (rhs.f_, rhs.f_+64, f_);
return *this;
}
Q: What happens if any copy fails? Maybe Bar will have to copy heavy resources under the hood. It can fail, it will.
A: At the time-point of exception, all objects copied so far will remain like that.
This means that our Foo is now in inconsistent and unpredictable state. To give it transaction semantics, we need to build up the new state fully or not at all, and then use operations that cannot throw to implant the new state in our Foo. Finally, we need to clean up the interim state.
The solution is to use the copy and swap idiom (http://gotw.ca/gotw/059.htm).
First, we refine our copy constructor:
Foo (Foo const &f) : f_(0), b_(0) {
try {
b_ = new Bar[64];
f_ = new Frob[64];
std::copy (rhs.b_, rhs.b_+64, b_); // if this throws, all commited copies will be thrown away
std::copy (rhs.f_, rhs.f_+64, f_);
} catch (std::exception &e) {
delete [] f_; // Note: it is safe to delete null-pointers -> nothing happens
delete [] b_;
throw; // don't forget to abort this object, do not let it come to life
}
}
Then, we define a non-throwing swap function
class Foo {
public:
friend void swap (Foo &, Foo &);
};
void swap (Foo &lhs, Foo &rhs) {
std::swap (lhs.f_, rhs.f_);
std::swap (lhs.b_, rhs.b_);
}
Now we can use our new exception safe copy-constructor and exception-safe swap-function to write an exception-safe copy-assignment-operator:
Foo& operator= (Foo const &rhs) {
Foo tmp (rhs); // if this throws, everything is released and exception is propagated
swap (tmp, *this); // cannot throw
return *this; // cannot throw
} // Foo::~Foo() is executed
What happened? At first, we build up new storage and copy rhs' into it. This may throw, but if it does, our state is not altered and the object remains valid.
Then, we exchange our guts with the temporary's guts. The temporary gets what is not needed anymore, and releases that stuff at the end of scope. We effectively used tmp as a garbage can, and properly choose RAII as the garbage collection service.
You may want to look at http://gotw.ca/gotw/059.htm or read Exceptional C++ for more details on this technique and on writing exception safe code.
Putting it together
Summary of what can't throw or is not allowed to throw:
copying primitive types never throws
destructors are not allowed to throw (because otherwise, exception safe code would not be possible at all)
swap functions shall not throw** (and C++ programmers as well as the whole standard library expect it to not throw)
And here is finally our carefully crafted, exception safe, corrected version of Foo:
class Foo {
public:
Foo() : b_(0), f_(0)
{
try {
b_ = new Bar[64];
f_ = new Frob[64];
} catch (std::exception &e) {
delete [] f_; // Note: it is safe to delete null-pointers -> nothing happens
delete [] b_;
throw; // don't forget to abort this object, do not let it come to life
}
}
Foo (Foo const &f) : f_(0), b_(0)
{
try {
b_ = new Bar[64];
f_ = new Frob[64];
std::copy (rhs.b_, rhs.b_+64, b_);
std::copy (rhs.f_, rhs.f_+64, f_);
} catch (std::exception &e) {
delete [] f_;
delete [] b_;
throw;
}
}
~Foo()
{
delete [] f_;
delete [] b_;
}
Foo& operator= (Foo const &rhs)
{
Foo tmp (rhs); // if this throws, everything is released and exception is propagated
swap (tmp, *this); // cannot throw
return *this; // cannot throw
} // Foo::~Foo() is executed
friend void swap (Foo &, Foo &);
private:
Bar *b_;
Frob *f_;
};
void swap (Foo &lhs, Foo &rhs) {
std::swap (lhs.f_, rhs.f_);
std::swap (lhs.b_, rhs.b_);
}
Compare that to our initial, innocent looking code that is evil to the bones:
class Foo {
public:
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
private:
Bar *b_;
Frob *f_;
};
You better don't add more variables to it. Sooner or later, you will forget to add proper code at some place, and your whole class becomes ill.
Or make it non-copyable.
class Foo {
public:
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
Foo (Foo const &) = delete;
Foo& operator= (Foo const &) = delete;
private:
Bar *b_;
Frob *f_;
};
For some classes this makes sense (streams, for an instance; to share streams, be explicit with std::shared_ptr), but for many, it does not.
The real solution.
class Foo {
public:
Foo() : b_(64), f_(64) {}
private:
std::vector<Bar> b_;
std::vector<Frob> f_;
};
This class has clean copying semantics, is exception safe (remember: being exception safe does not mean to not throw, but rather to not leak and possibly have transaction semantics), and does not leak.
In just about any situation, std::vector is preferable. It has a destructor to free the memory, whereas manually managed memory must be explicitly deleted once you've finished with it. It is very easy to introduce memory leaks, for example if something throws an exception before it is deleted. For example:
void leaky() {
int * stuff = new int[10000000];
do_something_with(stuff);
delete [] stuff; // ONLY happens if the function returns
}
void noleak() {
std::vector<int> stuff(10000000);
do_something_with(stuff);
} // Destructor called whether the function returns or throws
It is also more convenient if you need to resize or copy the array.
The only reason to prefer a raw array is if you have extreme performance or memory limitations. vector is a larger object than a pointer (containing size and capacity information); and it will sometimes value-initialise its objects, while a raw array will default-initialise them (which, for trivial types, means they are left uninitialised).
In the rare cases when these issues might be important, you should consider std::unique_ptr<int[]>; it has a destructor which will prevent memory leaks, and has no run-time overhead when compared to a raw array.
I don't think that there's ever a case where new int[size] is preferable. You'll sometimes see it in pre-standard code, but even then, I don't think it was ever a good solution; in pre-standard days, if you didn't have an equivalent to std::vector in your tool kit, you wrote one. The only reasons you might want to use a new int[size] is in the implementation of a pre-standard vector class. (My own separated allocation and initialization, like the containers in the standard library, but this might be overkill for a very simple vector class.)
Even though both methods allocates dynamic memory, one is an object made for handling data of arbitrary length (std::vector<T>), while the other is just a pointer to a sequential line of memory slots of size N (ints in this case).
Among other differences
A std::vector<T> will automatically resize the allocated memory for your data if you try to append a new value and it runs out of space. A int * will not.
A std::vector<T> will free the allocated memory when the vector goes out of scope, a int * will not.
A int * will have little to no overhead (compared to the vector), though std::vector<T> isn't exactly a new thing and is normally very optimized. Your bottle neck will probably be elsewhere.
But a std::vector<int> will always consume more memory than a int *, and some operations will always take a little more time.
So if there are memory/CPU limitations and you want to shave off every single cycle that you possible can.. use an int *.
There are situations where one is definitely preferable over the other!
When you need "raw"/"real" memory and full control over it, operator new is your best bet.
For example when you are using placement new.
by raw/real memory I mean something that is not managed through a wrapper-container, such as std::vector<T>.
When you are looking for a container to handle arbitrary and don't want to reinvent the wheel regarding memory management; std::vector<T> (or any other appropriate STL container)
Can anyone give me advice as to which is better?
Vector is better when
You haven't learned to do manual memory management.
You have learned of it, but aren't confident yet.
You think you know how to do it, but are unwittingly overconfident.
You really know what you're doing, but might make a mistake.
You are a guru and none of the above applies, but your code might be later maintained by a colleague, for whom any of the above does apply.
...
Pretty much always.
Manual memory management can easily and often does lead to memory leaks, and worse yet, undefined behaviour.
Internally the vector do exactly the same also it will make care about the memory release. So there is no any reason to use the new operator. std::vector is a part of c++, it is standard, it is tested and it is safe, don't use the raw pointer when you have some standard way to do your work.
If you need a dynamically sized sequence of objects, use a vector. If you need to allocate raw memory and manage that memory yourself, allocate memory. You will find that sometimes vectors are more useful, and at other times a flat memory buffer is better.

Creating c++ object on the stack, trying hard not to ever allocate

Suppose I have a class
class A {
public:
A(int i);
~A();
private:
B b; // Want <- this guy to be constructed with i in A's constructor!
};
I want b to be constructed in the constructor with particular parameters that aren't known until A is constructed. If I were to do the following in A's constructor:
A::A(int i) {
B b(i);
// Or even if I try to do b = B::B(i);
}
I notice that b get's allocated twice on the stack! aghghg.
Then I found out that what I can do in A's constructor is:
A::A() : b(B::B(7)) {
}
And b only gets allocated on the stack once!
But this is pretty clunky. Anyone got a better idea? Remember, the constructor should only be called once!
Is this the standard way of allocating objects NON-dynamically with important parameters? What if we can shove b's construction into that fancy argument list thing!? You're forced to either dynamically allocate, or construct TWICE on the stack!
Bonus Question: When does b get deallocated? Is it after or right before A's destructor
I'm sorry to say but you have it all wrong.
What you need to do is to pick up a good beginner's C++ book. This is such a fundamental part of the language that if you don't understand this you will struggle when dealing with non-trivial C++ code.
That being said, when an object is about to be created, all subobjects will be created first. If you need to pass parameters to those subobject constructors, you need to create what's called an initializer list:
A::A(int i) : b(i) {}
The stuff that follows the colon and before the first brace is the initializer list. Only constructors can have them. What's going on here is that we pass the value of i to the b subobject's constructor. This happens before the constructor for A is called!
So for your case, the order of construction is:
The b subobject
The A object itself
The order of destruction is the complete opposite process.
does
A::A() : b(7) { }
not work?
Edit: I'm at work, so I'll do a more comprehensive edit later using some profile stuff to see what gcc does w.r.t. deallocation. I suspect that nobar is right and all deallocation happens at once.
b(B::B(7)) works as well as b(7) because B::B(7) creates a temporary B variable. b is then copy-constructed from that temporary. A decent optimizing compiler should be able to reduce the second case to the first but:
b(7) is more idiomatic -- other c++ programmers will recognize is more easily
You really don't know for sure what a compiler will do.
if B is not copy-constructible, or expensive to copy-construct, you may not want to deal with the added overhead if, like most, you turn off optimizations for debugging.
It only takes a small modification to your program to demonstrate the order of construction and destruction.
#include <iostream>
using std::cerr;
class B
{
public:
B( int ) { cerr<<"B()\n"; ;}
~B() { cerr<<"~B()\n"; }
};
class A
{
B b;
public:
A( int i ) : b(i) { cerr<<"A()\n"; }
~A() { cerr<<"~A()\n"; }
};
int main()
{
A a(7);
}
Here's the output:
$ make destructor_order && ./destructor_order
B()
A()
~A()
~B()

Will the below code cause memory leak in c++

class someclass {};
class base
{
int a;
int *pint;
someclass objsomeclass;
someclass* psomeclass;
public:
base()
{
objsomeclass = someclass();
psomeclass = new someclass();
pint = new int();
throw "constructor failed";
a = 43;
}
}
int main()
{
base temp();
}
In the above code, the constructor throws. Which objects will be leaked, and how can the memory leaks be avoided?
int main()
{
base *temp = new base();
}
How about in the above code? How can the memory leaks be avoided after the constructor throws?
Yes it will leak memory. When the constructor throws, no destructor will be called (in this case you don't show a destructor that frees the dynamically allocated objects, but lets assume you had one).
This is a major reason to use smart pointers - since the smart poitners are full fledged objects, they will get destructors called during the exception's stack unwind and have the opportunity to free the memory.
If you use something like Boost's scoped_ptr<> template, your class could look more like:
class base{
int a;
scoped_ptr<int> pint;
someclass objsomeclass;
scoped_ptr<someclass> psomeclass;
base() :
pint( new int),
objsomeclass( someclass()),
psomeclass( new someclass())
{
throw "constructor failed";
a = 43;
}
}
And you would have no memory leaks (and the default dtor would also clean up the dynamic memory allocations).
To sum up (and hopefully this also answers the question about the
base* temp = new base();
statement):
When an exception is thrown inside a constructor there are several things that you should take note of in terms of properly handling resource allocations that may have occured in the aborted construction of the object:
the destructor for the object being constructed will not be called.
destructors for member objects contained in that object's class will be called
the memory for the object that was being constructed will be freed.
This means that if your object owns resources, you have 2 methods available to clean up those resources that might have already been acquired when the constructor throws:
catch the exception, release the resources, then rethrow. This can be difficult to get correct and can become a maintenance problem.
use objects to manage the resource lifetimes (RAII) and use those objects as the members. When the constructor for your object throws an exception, the member objects will have desctructors called and will have an opportunity to free the resource whose lifetimes they are responsible for.
Both new's will be leaked.
Assign the address of the heap created objects to named smart pointers so that it will be deleted inside the smart pointers destructor that get call when the exception is thrown - (RAII).
class base {
int a;
boost::shared_ptr<int> pint;
someclass objsomeclass;
boost::shared_ptr<someclass> psomeclass;
base() :
objsomeclass( someclass() ),
boost::shared_ptr<someclass> psomeclass( new someclass() ),
boost::shared_ptr<int> pint( new int() )
{
throw "constructor failed";
a = 43;
}
};
Now psomeclass & pint destructors will be called when the stack unwind when the exception is thrown in the constructor, and those destructors will deallocate the allocated memory.
int main(){
base *temp = new base();
}
For ordinary memory allocation using (non-plcaement) new, memory allocated by the operator new is freed automatically if the constructor throws an exception. In terms of why bother freeing individual members (in response to comments to Mike B's answer), the automatic freeing only applies when an exception is thrown in a constructor of an object being new'ly allocated, not in other cases. Also, the memory that is freed is those allocated for the object members, not any memory you might have allocated say inside the constructor. i.e. It would free the memory for the member variables a, pint, objsomeclass, and psomeclass, but not the memory allocated from new someclass() and new int().
I believe that the top answer is wrong and would still leak memory.
The destructor for the class members will not be called if the constructor throws an exception (because it never completed its initialization, and perhaps some members have never reached their constructor calls).
Their destructors are only called during the class's destructor call. That only makes sense.
This simple program demonstrates it.
#include <stdio.h>
class A
{
int x;
public:
A(int x) : x(x) { printf("A constructor [%d]\n", x); }
~A() { printf("A destructor [%d]\n", x); }
};
class B
{
A a1;
A a2;
public:
B()
: a1(3),
a2(5)
{
printf("B constructor\n");
throw "failed";
}
~B() { printf("B destructor\n"); }
};
int main()
{
B b;
return 0;
}
With the following output (using g++ 4.5.2):
A constructor [3]
A constructor [5]
B constructor
terminate called after throwing an instance of 'char const*'
Aborted
If your constructor fails partway then it is your responsibility to deal with it. Worse, the exception may be thrown from your base class' constructor!
The way to deal with these cases is by employing a "function try block" (but even then you must carefully code the destruction of your partially initialized object).
The correct approach to your problem would then be something like this:
#include <stdio.h>
class A
{
int x;
public:
A(int x) : x(x) { printf("A constructor [%d]\n", x); }
~A() { printf("A destructor [%d]\n", x); }
};
class B
{
A * a1;
A * a2;
public:
B()
try // <--- Notice this change
: a1(NULL),
a2(NULL)
{
printf("B constructor\n");
a1 = new A(3);
throw "fail";
a2 = new A(5);
}
catch ( ... ) { // <--- Notice this change
printf("B Cleanup\n");
delete a2; // It's ok if it's NULL.
delete a1; // It's ok if it's NULL.
}
~B() { printf("B destructor\n"); }
};
int main()
{
B b;
return 0;
}
If you run it you will get the expected output where only the allocated objects are destroyed and freed.
B constructor
A constructor [3]
B Cleanup
A destructor [3]
terminate called after throwing an instance of 'char const*'
Aborted
You can still work it out with smart shared pointers if you want to, with additional copying. Writing a constructor similar to this:
class C
{
std::shared_ptr<someclass> a1;
std::shared_ptr<someclass> a2;
public:
C()
{
std::shared_ptr<someclass> new_a1(new someclass());
std::shared_ptr<someclass> new_a2(new someclass());
// You will reach here only if both allocations succeeded. Exception will free them both since they were allocated as automatic variables on the stack.
a1 = new_a1;
a2 = new_a2;
}
}
Good luck,
Tzvi.
If you throw in a constructor, you should clean up everything that came before the call to throw. If you are using inheritance or throwing in a destructor, you really shouldn't be. The behaviour is odd (don't have my standard handy, but it might be undefined?).
Yes, that code will leak memory. Blocks of memory allocated using "new" are not freed when an exception is raised. This is part of the motivation behind RAII.
To avoid the memory leak, try something like this:
psomeclass = NULL;
pint = NULL;
/* So on for any pointers you allocate */
try {
objsomeclass = someclass();
psomeclass = new someclass();
pint = new int();
throw "constructor failed";
a = 43;
}
catch (...)
{
delete psomeclass;
delete pint;
throw;
}
Everything you "new" needs to be deleted, or you'll cause a memory leak. So these two lines:
psomeclass = new someclass();
pint = new int();
Will cause memory leaks, because you need to do:
delete pint;
delete psomeclass;
In a finally block to avoid them being leaked.
Also, this line:
base temp = base();
Is unnecessary. You just need to do:
base temp;
Adding the "= base()" is unnecessary.
you need to delete psomeclass... Its not necessary to clean up the integer...
RWendi