Why does boost not have a make_scoped()? - c++

Boost's make_shared() function promises to be exception-safe while attempting to create a shared_ptr.
Why is there no make_scoped() equivalent? Is there a common best practice?
Here's a code example from the boost::scoped_ptr documentation that seems unsafe to me:
boost::scoped_ptr<Shoe> x(new Shoe);
This line of code will do these three things in order:
Allocate heap memory for Shoe
Call the constructor for Shoe
Call the constructor for boost::scoped_ptr<Shoe>
If the constructor for Shoe throws an exception, memory will be leaked. (see R. Martinho Fernandes answer) The scoped_ptr won't handle the deallocation because it hasn't been constructed yet.
Is this an oversight? Or is there a solution that I've failed to notice?

scoped_ptr predates move semantics and is noncopyable by design. Thus, make_scoped would be impossible to implement because in order to return an object from a function, its type must either be movable or copyable.

If the constructor fails, no memory is leaked. That's part of the semantics of new, no smart pointers involved:
struct Foo { Foo() { throw 23; } };
new Foo(); // no memory leaked
The added exception safety provided by make_shared comes from when you're initializing two shared_ptrs in an expression and the two initializations are not sequenced, as is the case in function call arguments:
struct Bar {
Bar(bool fail) {
if(fail) throw 17;
}
}
f(shared_ptr<Bar>(new Bar(true)), shared_ptr<Bar>(new Bar(false)));
Since there is no sequencing between the evaluations of new Bar(true), shared_ptr<Bar>(new Bar(true)), new Bar(false) and shared_ptr<Bar>(new Bar(false)), the following could happen:
new Bar(false) is evaluated and succeeds: memory is allocated;
new Bar(true) is evaluated and fails: it doesn't leak memory resulting from this evaluation;
No shared_ptr was constructed at this time, and so the memory allocated in #1 is now leaked.

If Shoe throws then Shoe isn't constructed so there is nothing scoped_ptr can really do. No?
The scoped_ptr x is on the stack and will get cleaned up on scope exit.

Related

c++ operator new how this works internally

For example I have a simple code:
class B
{
};
class A
{
B b;
public:
A()
{
throw 1;
}
};
int main()
{
A* a = 0;
try
{
a = new A;
}
catch (int)
{
}
}
Constructor A throws exception, then destructor will not be called. But destructor for B will be called. Memory in the heap will not be allocated. My question how this works internally? What will be first: constructing A or allocating memory in the heap? So, if allocating is the first, how deallocating will be handled if there are exception? Othervise, if constructing A is the first, how it's copiing to the heap?
The memory is allocated.
The constructor of A is called.
The constructor of A calls the constructor of B.
The constructor of A throws.
As a part of the standard exception handling procedure, the destructor of B is called (RAII at work).
The stack unwinds to the caller (main).
The memory is deallocated (because the object wasn't constructed successfully).
The destructor of A isn't called because the object was not fully constructed. However, the members which were fully constructed are still destroyed.
The memory is deallocated automatically in pretty much the same way as local variables are destroyed when the control leaves the block. If you're familiar with Java and/or C#, think of it as an invisible try-finally construct. Or a series of such constructs.
What will be first: constructing A or allocating memory in the heap?
Unless there's memory, there's no space in which the object can be constructed. Memory allocation always goes first; then the code proceeds with initialization. This applies to all kinds of memory allocations, not only of the dynamic variety, because constructors need to have a valid address of this before they start initializing the object.
If allocating is the first, how deallocating will be handled if there are exception?
The compiler emits special code that handles the "magic" here. This code will run destructors for all base classes, and for members, such as B, that have been fully constructed by the time the code entered A's constructor.

Can initialization `int * p = malloc(1000);` also be dealt in RAII style?

What I understand from RAII is whenever you need to allocate memory manually with new etc. you need to free it too. So, instead of freeing it manually, you should create classes with constructor and destructor to do the job.
So, what are the following people talking about?
From: The meaning of the term - Resource Acquisition Is Initialization
The problem is that int * p = malloc(1000); is also initialization of an (integer) object, but it's not the kind of initialization we mean in the context of RAII.
...
#Fred: Indeed. int* is not a RAII type because it doesn't do cleanup. So it's not what RAII means, even though it is what RAII literally says.
Well, I know malloc is used in C, and new is used in C++.
Using malloc per se is not RAII because the resources are not freed when the variable goes out of scope, causing leaks of memory. You can make it RAII if you wrap this inside a class and free the resources in the destructor, because local class instances do die when they go out of scope. However, it should be noted what is being discussed here: the int * type is not RAII, and if you enclose it in a RAII type it still isn't. The wrapper doesn't make it RAII, so the RAII type here is the wrapper, not the pointer itself.
As requested in the comments: RAII stands for Resource Acquisition Is Initialisation and it's a design paradigm that combines the allocation of resources with the initialisation and destruction of objects. You don't seem far from understanding it: when an object is instantiated it allocates all the necessary resources (memory, file descriptors, streams, and so on) and frees them when it goes out of scope or the object is otherwise destructed. This is a common paradigm in C++ because C++ classes are RAII (that is, they die when they go out of scope) and as such it's easy to guarantee proper cleanup. The obvious upside being that you don't need to worry about manual cleanup and tracking variable lifetime.
On a related note, notice that this refers to stack allocation, not heap. What this means is that whatever the means you use for allocation (new/malloc vs delete/free) it still isn't RAII; memory that is allocated dynamically does not get magically freed, that's a given. When a variable is allocated on the stack (local variables) they are destroyed when the scope dies.
Example:
class MyObject
{
public:
MyObject()
{
// At this point resources are allocated (memory, files, and so on)
// In this case a simple allocation.
// malloc would have been just as fine
this->_ptr = new int;
}
~MyObject()
{
// When the object is destructed all resources are freed
delete this->_ptr;
}
private:
int * _ptr;
};
The previous sample code implements a RAII wrapper over a native pointer. Here's how to use it:
void f()
{
MyObject obj;
// Do stuff with obj, not including cleanup
}
In the previous example the int pointer is allocated when the variable is instantiated (at declaration time) and freed when the f call terminates, causing the variable to go out of scope and calling its destructor.
Note: As mentioned in the comments by Jarod42 the given example does not conform to the rule of 3 or the rule of 5, which are common thumb rules in C++. I would rather not add complexity to the given example, and as such I'll complete it here. These rules indicate that, if a method from a given set is implemented, then all methods of the set should be implemented, and those methods are the copy and move constructors, the assignment and move operators, and the destructor. Notice at first that this is a general rule, which means that is not mandatory. For instance, immutable objects should not implement assignment and move operators at all. In this case, if the object is to implement these operators it would probably imply reference counting, as multiple copies of the resource exist the destructor must not free the resources until all copies are destroyed. I believe that such an implementation would fall out of scope and as such I'm leaving it out.
By example
NOT RAII:
void foo()
{
int* p = malloc(sizeof(int) * N);
// do stuff
free(p);
}
also NOT RAII:
void foo()
{
int* p = new int[N];
// do stuff
delete[] p;
}
RAII:
struct MyResourceManager
{
int* p;
MyResourceManager(size_t n) : p(malloc(sizeof(int) * n)) { }
~MyResourceManager() { free(p); }
};
void foo()
{
MyResourceManager resource(N);
// doing stuff with resource.p
}
Also RAII (better):
struct MyResourceManager
{
int* p;
MyResourceManager(size_t n) : p(new int[n]) { }
~MyResourceManager() { delete[] p; }
};
void foo()
{
MyResourceManager resource(N);
// doing stuff with resource.p
}
Also RAII (best for this use case):
void foo()
{
std::unique_ptr<int[]> p(new int[N]);
// doing stuff with p
}
RAII is not use of operator new nor is it use of malloc().
It essentially means that, in the process of initialising an object, all resources that object needs to function are allocated. The counterpart requirement is that, in the process of destroying the object, that the resources it has allocated are released.
The concept applies to memory (most commonly), but also to any other resource that needs to be managed - file handles (opened in initialisation, closed when done), mutexes (grabbed in initialisation, released when done), communication ports, etc etc.
In C++, RAII is typically implemented by performing initialisation in constructors of an object, and the release of resources is done in the destructor. There are wrinkles such as other member functions possibly reallocating (e.g. resizing a dynamically allocated array) - in those cases, the member functions must ensure they do things in a way to ensure all resources allocated are appropriately released when the destructor is done. If there are multiple constructors, they need to do things consistently. You'll see this described as something like the constructor setting a class invariant (i.e. that resources are allocated correctly), member functions maintaining that invariant, and the destructor being able to clean up because the invariant is maintained.
The advantage of RAII - if done right - is that non-static variable lifetime is managed by the compiler (when an object goes out of scope, its destructor is invoked). So, the resources will be cleaned up correctly.
However, the requirement is always that the destructor does the cleanup (or that data members of the class have their own destructors that do the required cleanup). If constructor initialises an int * using malloc(), then it is not enough to assume the destructor will clean up - the destructor must pass that pointer to free(). If you don't do that, the C++ compiler will not magically find some way to release the memory for you (the pointer will no longer exist when the destructor is done, but the allocated memory it pointed to will not be released - so the result is a memory leak). C++ does not inherently use garbage collection (which is a trap for people used to garbage collected languages assuming that garbage collection will occur).
And it is undefined behaviour to use malloc() to allocate memory, and operator delete in any form to release it.
It is generally preferable to not use malloc() and free() in C++, because they do not work well with object construction and destruction (invoking constructors and destructors). Use operator new instead (and for whatever form of operator new you use, use the corresponding operator delete). Or, better yet, use standard C++ containers (std::vector, etc) as much as possible to avoid the need to worry about manually releasing memory you allocate.
Destruction of int* doesn't release the resources. It isn't safe to just let it go out of scope, so it isn't RAII.
The int * could be be a member of a class that deletes the int* in its destructor, which is essentially what unique_ptr of an int does. You make things like this RAII by wrapping them in code that encapsulates the deletion.
The discussion is about code that literally does initialization upon resource acquisition, but doesn't follow the RAII design.
In the shown example with malloc, 1000 bytes of memory are allocated (resource allocation) and a variable p (pointer to int) is initialized with the result (initialization). However, this is obviously not an example of RAII, because the object (of type int *) doesn't take care of the acquired resource in its destructor.
So no, malloc itself can not be RAII in some situations, it is an example of non-RAII code that nevertheless does "Initialization on Resource Acquisition" which might be confusing for new c++ programmers on first glance.
In C++, unique_ptr represents a pointer that "owns" the thing it points to. You can supply the release function as second argument:
std::unique_ptr<int[], std::function<void(void*)>>
p( (int *)malloc(1000 * sizeof(int)), std::free );
Of course, there's not much reason to do this instead of just using new (when the default deleter delete will do the right thing).
Yes, you can deal with int * p = malloc(1000); using the RAII paradigm. Smart pointers and std::vector use a very similar technique though they don't probably use malloc and prefer to use new instead.
Here's a very simplistic look at what one can do with malloc. MyPointer is far from being useful in a real application. Its only purpose is to demonstrate the principle of RAII.
class MyPointer
{
public:
MyPointer(size_t s) : p(malloc(s)) {}
~MyPionter() { free(p); }
int& operator[](size_t index) { return p[index]; }
private:
int* p;
};
int main()
{
// By initializing ptr you are acquiring resources.
// When ptr gets destructed, the resource is released.
MyPointer ptr(1000);
ptr[0] = 10;
std::cout << ptr[0] << std::endl;
}
The core idea behind RAII is:
Treat resource acquisition as though you are initializing an object.
Make sure the acquired resource(s) is(are) released when the object is destructed.
You can read more on RAII at Wikepedia.
So, what are the following people talking about?
What is RAII?
RAII in a nutshell is a very simple idea. It is the idea that no object may exist at all unless it is fully initialised.
Why is that good?
We now have a concrete guarantee that a 'half built' object cannot be accidentally used - because at no point in the logical flow of the program can it possibly exist.
How do we achieve it?
a) always manage resources (memory, files, mutex locks, database connections) in a class of their own which is specifically tailored to only managing that resource.
b) build complex logic out of collections of objects covered by [a]
c) Always throw if anything in the constructor fails (to guarantee that a failed object cannot exist)
d) if we are managing more than one resource in a class, we ensure that a failed construction cleans up the parts that have already been constructed (NOTE: this is hard [sometimes impossible], and why at this point you should be referred back to [a])
Sounds hard?
Initialising your objects completely in the initialiser list, while wrapping all external resources in a manager class (e.g. files, memory) achieves perfect RAII effortlessly.
What's the advantage?
Your program may now contain only logic which makes it easier to reason about and to read. The compiler will take care of all resource management perfectly.
Effortless Compound Resource Management
An example of RAII that's hard without manager classes and easy with them?
struct double_buffer
{
double_buffer()
: buffer1(std::nullptr) // NOTE: redundant zero construction
, buffer2(std::nullptr)
{
buffer1 = new char[100]; // new can throw!
try {
buffer2 = new char[100]; // if this throws we have to clean up buffer1
}
catch(...) {
delete buffer1; // clean up buffer1
throw; // rethrow because failed construction must throw!
}
}
// IMPORTANT!
// you MUST write or delete copy constructors, move constructor,
// plus also maybe move-assignment or move-constructor
// and you MUST write a destructor!
char* buffer1;
char* buffer2;
};
now the RAII version:
struct double_buffer
{
double_buffer()
: buffer1(new char[100]) // memory immediately transferred to manager
, buffer2(new char[100]) // if this throws, compiler will handle the
// correct cleanup of buffer1
{
// nothing to do here
}
// no need to write copy constructors, move constructor,
// move-assignment or move-constructor
// no need to write destructor
std::unique_ptr<char[]> buffer1;
std::unique_ptr<char[]> buffer2;
};
How does it improve my code?
some safe code that uses RAII:
auto t = merge(Something(), SomethingElse()); // pretty clear eh?
t.performAction();
the same code that does not use RAII:
TargetType t; // at this point uninitialised.
Something a;
if(a.construct()) {
SomethingElse b;
if (b.construct()) {
bool ok = merge_onto(t, a, b); // t maybe initialised here
b.destruct();
a.destruct();
if (!ok)
throw std::runtime_error("merge failed");
}
else {
a.destruct();
throw std::runtime_error("failed to create b");
}
}
else {
throw std::runtime_error("failed to create a");
}
// ... finally, we may now use t because we can (just about) prove that it's valid
t.performAction();
The difference
The RAII code is written solely in terms of logic.
The non-RAII code is 40% error handling and 40% lifetime management and only 20% logic. Furthermore, the logic is hidden in amongst all the other garbage, making even these 11 lines of code very hard to reason about.

segment fault for a simple std::shared_ptr construction case

From cppreference I learn that there is a constructor for std::shared_ptr:
template< class Y > explicit shared_ptr( Y* ptr );
And I tried a piece of code as follows:
#include <string>
#include <memory>
#include <iostream>
int main(void) {
/// block 1
{
std::shared_ptr<std::string> s1(new std::string("good"));
std::shared_ptr<std::string> s2(s1.get()); /// s2
std::cerr << s2.use_count() << std::endl;
}
/// block 2
{
std::shared_ptr<int> i1(new int(1));
std::shared_ptr<int> i2(i1.get()); /// i2
std::cerr << i2.use_count() << std::endl;
}
return 0;
}
It causes segment fault for block 1 but not for block 2, but both use_count are 1. The difference I can think about is that that int is a primitive type while std::string is managed by allocator.
I read bits/shared_ptr.h of gcc-4.9 and find that there is a post condition for this constructor:
use_count() == 1 && get() == __p
Question 1:
Should std::shared_ptr NOT constructed with a raw pointer that has been referenced by another smart pointer? In this sense, is the preferred way to use this constructor as follow?
std::shared_ptr<T>(new T(...));
Question 2:
Does the standard has explicit requirement for this constructor, or this post condition is ONLY for libstdc++?
Both of these cases are invalid uses of std::shared_ptr.
You cannot pass the same raw pointer to two std::shared_ptr constructors and expect well-defined results. Both std::shared_ptrs will believe that they own that pointer, and will attempt to delete it when they go out of scope.
This is a double free, and is invalid.
If you want to have two std::shared_ptrs that manage the same object, you can construct one of them with a raw pointer (or, better yet, use std::make_shared), and then copy construct/assign the second one from the first one. This way the memory will only be deallocated (and the destructor for the object fired) when the last of those std::shared_ptrs goes out of scope.
The reason you're getting a segmentation fault in the first case, and not the second one, is likely because int is a trivial type, and therefore you're not looking through a freed pointer to run the destructor of int, because it doesn't have one.
This is undefined behavior, we can see this by going to cppreference section for std::shared_ptr constructors says this (emphasis mine):
Constructing a shared_ptr using the raw pointer overload for an object
that is already managed by a shared_ptr leads to undefined behavior,
even if the object is of a type derived from
std::enable_shared_from_this (in other words, raw pointer overloads
assume ownership of the pointed-to object).
Both shared_ptr will attempt to delete the object they believe they now hold sole ownership for. We know this is undefined behavior by going to the draft C++ standard section 3.7.4.2 Deallocation functions which says:
If the argument given to a deallocation function in the standard
library is a pointer that is not the null pointer value (4.10), the
deallocation function shall deallocate the storage referenced by the
pointer, rendering invalid all pointers referring to any part of the
deallocated storage. Indirection through an invalid pointer value and
passing an invalid pointer value to a deallocation function have
undefined behavior. [...]
Ownership can only be shared by using copy construction or copy assignment. The same cppreference page provides a correct example using the copy constructor:
std::cout << "constructor with object\n";
std::shared_ptr<Foo> sh2(new Foo);
std::shared_ptr<Foo> sh3(sh2); // <- using copy construction
An alternative method to creating a shared_ptr is to use std::make_shared, which is safer:
Moreover, code such as f(std::shared_ptr(new int(42)), g()) can
cause a memory leak if g throws an exception because g() may be called
after new int(42) and before the constructor of shared_ptr. This
doesn't occur in f(std::make_shared(42), g()), since two function
calls are never interleaved.

Does the memory get released when I throw an exception?

I was debating with some colleagues about what happens when you throw an exception in a dynamically allocated class. I know that malloc gets called, and then the constructor of the class. The constructor never returns, so what happens to the malloc?
Consider the following example:
class B
{
public:
B()
{
cout << "B::B()" << endl;
throw "B::exception";
}
~B()
{
cout << "B::~B()" << endl;
}
};
void main()
{
B *o = 0;
try
{
o = new B;
}
catch(const char *)
{
cout << "ouch!" << endl;
}
}
What happens to the malloced memory o, does it leak? Does the CRT catch the exception of the constructor and deallocate the memory?
Cheers!
Rich
A call to
new B();
resolves in two things:
allocating with an operator new() (either the global one or a class specific one, potentially a placement one with the syntax new (xxx) B())
calling the constructor.
If the constructor throw, the corresponding operator delete is called. The case where the corresponding delete is a placement one is the only case where a placement delete operator is called without the syntax ::operator delete(). delete x; or delete[] x; don't call the placement delete operators and there is no similar syntax to placement new to call them.
Note that while the destructor of B will not be called, already constructed subobjects (members or B and base classes of B) will be destructed before the call to operator delete. The constructor which isn't called is the one for B.
When an exception is thrown from the constructor, the memory allocated by new is released, but the destructor of class B is not called.
In this case, your object, o, does not actually get constructed, and the memory allocated by new is freed. As such, the destructor does not get called. So you do NOT need to call:
delete o;
An interesting design pattern is RAII -- Resource Acquisition Is Initialization. In this pattern, you use a constructor to encapsulate the acquisition of a resource, and release the resource in the destructor. If the resource can not be acquired, you throw in the constructor -- much like your example. Thus if you have a valid object, you have the resource.
If the object is constructed, then you have successfully acquired the resource. This means that for the life of the object, you own the resource. When the object is deleted, the resource is released. If the object is never constructed, then you never acquired the resource. See wikipedia:
http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
From the C++ 2003 Standard 5.3.4/17 - New:
If any part of the object initialization described above terminates by throwing an exception and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed, after which the exception continues to propagate in the context of the new-expression. If no unambiguous matching deallocation function can be found, propagating the exception does not cause the object’s memory to be freed. [Note: This is appropriate when the called allocation function does not allocate memory; otherwise, it is likely to result in a memory leak. ]
So there may or may not be a leak - it depends on whether an appropriate deallocator can be found (which is normally the case, unless operator new/delete have been overridden).In the case where there's a suitable deallocator, the compiler is responsible for wiring in a call to it if the constructor throws.
Note that this is more or less unrelated to what happens to resources acquired in the constructor, which is what my first attempt at an answer discussed - and is a question that is discussed in many FAQs, articles, and postings.

Who deletes the memory allocated during a "new" operation which has exception in constructor?

I really can't believe I couldn't find a clear answer to this...
How do you free the memory allocated after a C++ class constructor throws an exception, in the case where it's initialised using the new operator. E.g.:
class Blah
{
public:
Blah()
{
throw "oops";
}
};
void main()
{
Blah* b = NULL;
try
{
b = new Blah();
}
catch (...)
{
// What now?
}
}
When I tried this out, b is NULL in the catch block (which makes sense).
When debugging, I noticed that the conrol enters the memory allocation routine BEFORE it hits the constructor.
This on the MSDN website seems to confirm this:
When new is used to allocate memory
for a C++ class object, the object's
constructor is called after the memory
is allocated.
So, bearing in mind that the local variable b is never assigned (i.e. is NULL in the catch block) how do you delete the allocated memory?
It would also be nice to get a cross platform answer on this. i.e., what does the C++ spec say?
CLARIFICATION: I'm not talking about the case where the class has allocated memory itself in the c'tor and then throws. I appreciate that in those cases the d'tor won't be called. I'm talking about the memory used to allocate THE object (Blah in my case).
You should refer to the similar questions here and here.
Basically if the constructor throws an exception you're safe that the memory of the object itself is freed again. Although, if other memory has been claimed during the constructor, you're on your own to have it freed before leaving the constructor with the exception.
For your question WHO deletes the memory the answer is the code behind the new-operator (which is generated by the compiler). If it recognizes an exception leaving the constructor it has to call all the destructors of the classes members (as those have already been constructed successfully prior calling the constructor code) and free their memory (could be done recursively together with destructor-calling, most probably by calling a proper delete on them) as well as free the memory allocated for this class itself. Then it has to rethrow the catched exception from the constructor to the caller of new.
Of course there may be more work which has to be done but I cannot pull out all the details from my head because they are up to each compiler's implementation.
If an object cannot complete destruction because the constructor throws an exception, the first thing to happen (this happens as part of the constructor's special handling) is that all member variables to have been constructed are destroyed - if an exception is thrown in the initializer list, this means that only elements for which the initializer has completed are destroyed.
Then, if the object was being allocated with new, the appropriate deallocation function (operator delete) is called with the same additional arguments that were passed to operator new. For instance, new (std::nothrow) SomethingThatThrows() will allocate memory with operator new (size_of_ob, nothrow), attempt to construct SomethingThatThrows, destroy any members that were successfully constructed, then call operator delete (ptr_to_obj, nothrow) when an exception is propagated - it won't leak memory.
What you have to be careful is allocating several objects in succession - if one of the later ones throws, the previous ones will not be automatically be deallocated. The best way around this is with smart pointers, because as local objects their destructors will be called during stack unwinding, and their destructors will properly deallocate memory.
If the Constructor throws the memory allocated for the object is auto-magically returned to the system.
Note the destructor of the class that threw will not be called.
But the destructor of any base class (where the base constructor has completed) will also be called.
Note:
As most other people have noted members may need some clean up.
Members that have been fully initialized will have their destructors called, but if you have any RAW pointer members that you own (ie delete in the destructor) you will have to do some clean up before you do the throw (another reason not to use owned RAW pointers in your class).
#include <iostream>
class Base
{
public:
Base() {std::cout << "Create Base\n";}
~Base() {std::cout << "Destroy Base\n";}
};
class Deriv: public Base
{
public:
Deriv(int x) {std::cout << "Create Deriv\n";if (x > 0) throw int(x);}
~Deriv() {std::cout << "Destroy Deriv\n";}
};
int main()
{
try
{
{
Deriv d0(0); // All constructors/Destructors called.
}
{
Deriv d1(1); // Base constructor and destructor called.
// Derived constructor called (not destructor)
}
}
catch(...)
{
throw;
// Also note here.
// If an exception escapes main it is implementation defined
// whether the stack is unwound. By catching in main() you force
// the stack to unwind to this point. If you can't handle re-throw
// so the system exception handling can provide the appropriate
// error handling (such as user messages).
}
}
From the C++ 2003 Standard 5.3.4/17 - New:
If any part of the object initialization described above terminates by throwing an exception and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed, after which the exception continues to propagate in the context of the new-expression. If no unambiguous matching deallocation function can be found, propagating the exception does not cause the object’s memory to be freed. [Note: This is appropriate when the called allocation function does not allocate memory; otherwise, it is likely to result in a memory leak. ]
So there may or may not be a leak - it depends on whether an appropriate deallocator can be found (which is normally the case, unless operator new/delete have been overridden).In the case where there's a suitable deallocator, the compiler is responsible for wiring in a call to it if the constructor throws.
Note that this is more or less unrelated to what happens to resources acquired in the constructor, which is what my first attempt at an answer discussed - and is a question that is discussed in many FAQs, articles, and postings.
The long and short of it is that if you haven't made any allocations of other entities in you object(as in your example) then the memory that was allocated will be deleted automatically. However, any new statements(or anything else that directly manages memory) needs to be handled in a catch statement in the constructor, Otherwise the object is deleted without deleting it's subsequent allocations and you, my friend, have a leak.
Quoted from C++ FAQ (parashift.com):
[17.4] How should I handle resources if my constructors may throw
exceptions?
Every data member inside your object should clean up its own mess.
If a constructor throws an exception, the object's destructor is not
run. If your object has already done something that needs to be undone
(such as allocating some memory, opening a file, or locking a
semaphore), this "stuff that needs to be undone" must be remembered
by a data member inside the object.
For example, rather than allocating memory into a raw Fred* data
member, put the allocated memory into a "smart pointer" member object,
and the destructor of this smart pointer will delete the Fred
object when the smart pointer dies. The template std::auto_ptr is an
example of such as "smart pointer." You can also write your own
reference counting smart pointer. You can also use smart pointers
to "point" to disk records or objects on other machines.
By the way, if you think your Fred class is going to be allocated
into a smart pointer, be nice to your users and create a typedef
within your Fred class:
#include <memory>
class Fred {
public:
typedef std::auto_ptr<Fred> Ptr;
...
};
That typedef simplifies the syntax of all the code that uses your
objects: your users can say Fred::Ptr instead of
std::auto_ptr<Fred>:
#include "Fred.h"
void f(std::auto_ptr<Fred> p); // explicit but verbose
void f(Fred::Ptr p); // simpler
void g()
{
std::auto_ptr<Fred> p1( new Fred() ); // explicit but verbose
Fred::Ptr p2( new Fred() ); // simpler
...
}
The problem described is as old as the road to Rome, to use a Dutch saying. I have worked out the problem and a memory allocation for an object that might throw an exception looks as follows:
try
{
std::string *l_string =
(_heap_cleanup_tpl<std::string>(&l_string),
new std::string(0xf0000000, ' '));
delete l_string;
}
catch(std::exception &)
{
}
Before the actual call to the new-operator, a nameless (temporary) object is created, which receives the address of the allocated memory through a user-defined new-operator (see the rest of this answer). In case of normal programme execution, the temporary object passes the result of the new-operator (the newly created and fully constructed object, in our case a very very very long string) to the variable l_string. In case of an exception, the value is not passed on, but the destructor of the temporary object deletes the memory (without ofcourse calling the destructor of the main object).
It is a bit fuzzy way of dealing with the issue, but it works. Problems may arise because this solution requires a user-defined new-operator and a user-defined delete-operator to go allong with it. The user-defined new/delete-operators would have to call the C++-standard library's implementation of new/delete-operators, but I have left that out for briefity and relied on malloc() and free() instead.
It is not the final answer, but I think it is worth working this one out.
PS: There was an 'undocumented' feature in the code below, so I have made an improvement.
The code for the temporary object is as follows:
class _heap_cleanup_helper
{
public:
_heap_cleanup_helper(void **p_heap_block) :
m_heap_block(p_heap_block),
m_previous(m_last),
m_guard_block(NULL)
{
*m_heap_block = NULL;
m_last = this;
}
~_heap_cleanup_helper()
{
if (*m_heap_block == NULL) operator delete(m_guard_block);
m_last = m_previous;
}
void **m_heap_block, *m_guard_block;
_heap_cleanup_helper *m_previous;
static _heap_cleanup_helper *m_last;
};
_heap_cleanup_helper *_heap_cleanup_helper::m_last;
template <typename p_alloc_type>
class _heap_cleanup_tpl : public _heap_cleanup_helper
{
public:
_heap_cleanup_tpl(p_alloc_type **p_heap_block) :
_heap_cleanup_helper((void **)p_heap_block)
{
}
};
The user-defined new-operator is as follows:
void *operator new (size_t p_cbytes)
{
void *l_retval = malloc(p_cbytes);
if (
l_retval != NULL &&
*_heap_cleanup_helper::m_last->m_heap_block == NULL &&
_heap_cleanup_helper::m_last->m_guard_block == NULL
)
{
_heap_cleanup_helper::m_last->m_guard_block = l_retval;
}
if (p_cbytes != 0 && l_retval == NULL) throw std::bad_alloc();
return l_retval;
}
void operator delete(void *p_buffer)
{
if (p_buffer != NULL) free(p_buffer);
}
I think it's kind of wierd for a constructor to raise an exception.
Could you have a return value and test it in your main?
class Blah
{
public:
Blah()
{
if Error
{
this.Error = "oops";
}
}
};
void main()
{
Blah* b = NULL;
b = new Blah();
if (b.Error == "oops")
{
delete (b);
b = NULL;
}