Should you free an array if allocating that array threw an exception?
Clash Royale CLAN TAG#URR8PPP
up vote
6
down vote
favorite
I am having a potentially unstable class that someone else wrote, and I'm having to create an array of objects of that class. I mentioned that the class is unstable, so it may occasionally throw an exception in the default constructor. I don't have access to the source code, only the compiled binaries.
When I am allocating the dynamic array of these type of objects using new
, there is the chance that one of these bad objects may throw an exception. It is throwing a custom exception, not std::bad_alloc
.
Anyway, I need to make the program recover from the exception and just keep on chugging, albeit setting some error flags and what not. I think that I should delete
the memory associated with the array to prevent a memory leak.
My reasoning is that if the class throws an exception constructing an element somewhere in the middle of the array, that element won't be constructed properly, and all the future elements will be stopped constructing by the exception, but the previous elements will have been properly constructed since that happened before the exception was thrown. I am wondering, is it a good idea to call delete
in the catch (...)
? How would I go about solving this memory leak?
Badclass* array = nullptr;
try
array = new Badclass[10]; // May throw exceptions!
catch (...)
delete array;
array = nullptr;
// set error flags
This is the way I visualize this in the memory. Is this correct?
array 0 1 2 3 4 5 6 7 8 9
___ __________________________________
| ---------->| :) | :) | :) | :) | :( | | | | | |
|___| |____|____|____|____|____|_|_|_|_|_|
c++ exception-handling
 |Â
show 3 more comments
up vote
6
down vote
favorite
I am having a potentially unstable class that someone else wrote, and I'm having to create an array of objects of that class. I mentioned that the class is unstable, so it may occasionally throw an exception in the default constructor. I don't have access to the source code, only the compiled binaries.
When I am allocating the dynamic array of these type of objects using new
, there is the chance that one of these bad objects may throw an exception. It is throwing a custom exception, not std::bad_alloc
.
Anyway, I need to make the program recover from the exception and just keep on chugging, albeit setting some error flags and what not. I think that I should delete
the memory associated with the array to prevent a memory leak.
My reasoning is that if the class throws an exception constructing an element somewhere in the middle of the array, that element won't be constructed properly, and all the future elements will be stopped constructing by the exception, but the previous elements will have been properly constructed since that happened before the exception was thrown. I am wondering, is it a good idea to call delete
in the catch (...)
? How would I go about solving this memory leak?
Badclass* array = nullptr;
try
array = new Badclass[10]; // May throw exceptions!
catch (...)
delete array;
array = nullptr;
// set error flags
This is the way I visualize this in the memory. Is this correct?
array 0 1 2 3 4 5 6 7 8 9
___ __________________________________
| ---------->| :) | :) | :) | :) | :( | | | | | |
|___| |____|____|____|____|____|_|_|_|_|_|
c++ exception-handling
1
Ifnew
throws,array
was never assigned, so there is nothing for you todelete
. So even if the exception comes from constructing one of the elements, the language guarantees memory is released.
– BoBTFish
3 hours ago
@BoBTFish The thing is,new
is not doing the throwing,Badclass::Badclass()
is!
– Galaxy
3 hours ago
Nevertheless,new
is the thing that callsBadclass::Badclass()
, sonew
never completes
– Michael Veksler
3 hours ago
1
@Galaxy it doesn't matter. If the requested operation (allocate and construct this sequence of things) throws, everything done to that point related to those two activities is wound back. That includes both the allocation, and any objects that were successfully constructed (and array request of ten objects fulfilling five, then throwing, will fire destructors for the five that constructed successfully, in reverse order of construction, before relinquishing the memory itself and officiating the throw).
– WhozCraig
3 hours ago
1
Its based on success of requested operation. The request could not be fulfilled. Therefore, whatever could be is undone and the exception is thrown. That includes the destruction of already-constructed elements. Not that anyone would do any of this (you would likely just use astd::vector
and be done with it, or have a darn good reason not to).
– WhozCraig
3 hours ago
 |Â
show 3 more comments
up vote
6
down vote
favorite
up vote
6
down vote
favorite
I am having a potentially unstable class that someone else wrote, and I'm having to create an array of objects of that class. I mentioned that the class is unstable, so it may occasionally throw an exception in the default constructor. I don't have access to the source code, only the compiled binaries.
When I am allocating the dynamic array of these type of objects using new
, there is the chance that one of these bad objects may throw an exception. It is throwing a custom exception, not std::bad_alloc
.
Anyway, I need to make the program recover from the exception and just keep on chugging, albeit setting some error flags and what not. I think that I should delete
the memory associated with the array to prevent a memory leak.
My reasoning is that if the class throws an exception constructing an element somewhere in the middle of the array, that element won't be constructed properly, and all the future elements will be stopped constructing by the exception, but the previous elements will have been properly constructed since that happened before the exception was thrown. I am wondering, is it a good idea to call delete
in the catch (...)
? How would I go about solving this memory leak?
Badclass* array = nullptr;
try
array = new Badclass[10]; // May throw exceptions!
catch (...)
delete array;
array = nullptr;
// set error flags
This is the way I visualize this in the memory. Is this correct?
array 0 1 2 3 4 5 6 7 8 9
___ __________________________________
| ---------->| :) | :) | :) | :) | :( | | | | | |
|___| |____|____|____|____|____|_|_|_|_|_|
c++ exception-handling
I am having a potentially unstable class that someone else wrote, and I'm having to create an array of objects of that class. I mentioned that the class is unstable, so it may occasionally throw an exception in the default constructor. I don't have access to the source code, only the compiled binaries.
When I am allocating the dynamic array of these type of objects using new
, there is the chance that one of these bad objects may throw an exception. It is throwing a custom exception, not std::bad_alloc
.
Anyway, I need to make the program recover from the exception and just keep on chugging, albeit setting some error flags and what not. I think that I should delete
the memory associated with the array to prevent a memory leak.
My reasoning is that if the class throws an exception constructing an element somewhere in the middle of the array, that element won't be constructed properly, and all the future elements will be stopped constructing by the exception, but the previous elements will have been properly constructed since that happened before the exception was thrown. I am wondering, is it a good idea to call delete
in the catch (...)
? How would I go about solving this memory leak?
Badclass* array = nullptr;
try
array = new Badclass[10]; // May throw exceptions!
catch (...)
delete array;
array = nullptr;
// set error flags
This is the way I visualize this in the memory. Is this correct?
array 0 1 2 3 4 5 6 7 8 9
___ __________________________________
| ---------->| :) | :) | :) | :) | :( | | | | | |
|___| |____|____|____|____|____|_|_|_|_|_|
c++ exception-handling
c++ exception-handling
asked 3 hours ago


Galaxy
522315
522315
1
Ifnew
throws,array
was never assigned, so there is nothing for you todelete
. So even if the exception comes from constructing one of the elements, the language guarantees memory is released.
– BoBTFish
3 hours ago
@BoBTFish The thing is,new
is not doing the throwing,Badclass::Badclass()
is!
– Galaxy
3 hours ago
Nevertheless,new
is the thing that callsBadclass::Badclass()
, sonew
never completes
– Michael Veksler
3 hours ago
1
@Galaxy it doesn't matter. If the requested operation (allocate and construct this sequence of things) throws, everything done to that point related to those two activities is wound back. That includes both the allocation, and any objects that were successfully constructed (and array request of ten objects fulfilling five, then throwing, will fire destructors for the five that constructed successfully, in reverse order of construction, before relinquishing the memory itself and officiating the throw).
– WhozCraig
3 hours ago
1
Its based on success of requested operation. The request could not be fulfilled. Therefore, whatever could be is undone and the exception is thrown. That includes the destruction of already-constructed elements. Not that anyone would do any of this (you would likely just use astd::vector
and be done with it, or have a darn good reason not to).
– WhozCraig
3 hours ago
 |Â
show 3 more comments
1
Ifnew
throws,array
was never assigned, so there is nothing for you todelete
. So even if the exception comes from constructing one of the elements, the language guarantees memory is released.
– BoBTFish
3 hours ago
@BoBTFish The thing is,new
is not doing the throwing,Badclass::Badclass()
is!
– Galaxy
3 hours ago
Nevertheless,new
is the thing that callsBadclass::Badclass()
, sonew
never completes
– Michael Veksler
3 hours ago
1
@Galaxy it doesn't matter. If the requested operation (allocate and construct this sequence of things) throws, everything done to that point related to those two activities is wound back. That includes both the allocation, and any objects that were successfully constructed (and array request of ten objects fulfilling five, then throwing, will fire destructors for the five that constructed successfully, in reverse order of construction, before relinquishing the memory itself and officiating the throw).
– WhozCraig
3 hours ago
1
Its based on success of requested operation. The request could not be fulfilled. Therefore, whatever could be is undone and the exception is thrown. That includes the destruction of already-constructed elements. Not that anyone would do any of this (you would likely just use astd::vector
and be done with it, or have a darn good reason not to).
– WhozCraig
3 hours ago
1
1
If
new
throws, array
was never assigned, so there is nothing for you to delete
. So even if the exception comes from constructing one of the elements, the language guarantees memory is released.– BoBTFish
3 hours ago
If
new
throws, array
was never assigned, so there is nothing for you to delete
. So even if the exception comes from constructing one of the elements, the language guarantees memory is released.– BoBTFish
3 hours ago
@BoBTFish The thing is,
new
is not doing the throwing, Badclass::Badclass()
is!– Galaxy
3 hours ago
@BoBTFish The thing is,
new
is not doing the throwing, Badclass::Badclass()
is!– Galaxy
3 hours ago
Nevertheless,
new
is the thing that calls Badclass::Badclass()
, so new
never completes– Michael Veksler
3 hours ago
Nevertheless,
new
is the thing that calls Badclass::Badclass()
, so new
never completes– Michael Veksler
3 hours ago
1
1
@Galaxy it doesn't matter. If the requested operation (allocate and construct this sequence of things) throws, everything done to that point related to those two activities is wound back. That includes both the allocation, and any objects that were successfully constructed (and array request of ten objects fulfilling five, then throwing, will fire destructors for the five that constructed successfully, in reverse order of construction, before relinquishing the memory itself and officiating the throw).
– WhozCraig
3 hours ago
@Galaxy it doesn't matter. If the requested operation (allocate and construct this sequence of things) throws, everything done to that point related to those two activities is wound back. That includes both the allocation, and any objects that were successfully constructed (and array request of ten objects fulfilling five, then throwing, will fire destructors for the five that constructed successfully, in reverse order of construction, before relinquishing the memory itself and officiating the throw).
– WhozCraig
3 hours ago
1
1
Its based on success of requested operation. The request could not be fulfilled. Therefore, whatever could be is undone and the exception is thrown. That includes the destruction of already-constructed elements. Not that anyone would do any of this (you would likely just use a
std::vector
and be done with it, or have a darn good reason not to).– WhozCraig
3 hours ago
Its based on success of requested operation. The request could not be fulfilled. Therefore, whatever could be is undone and the exception is thrown. That includes the destruction of already-constructed elements. Not that anyone would do any of this (you would likely just use a
std::vector
and be done with it, or have a darn good reason not to).– WhozCraig
3 hours ago
 |Â
show 3 more comments
2 Answers
2
active
oldest
votes
up vote
11
down vote
accepted
To answer the final question:
How would I go about solving this memory leak?
There is no memory leak. The leak would only happen if BadClass
itself dynamically allocated content and never freed it in its destructor. Since we're oblivious to your BadClass
implementation, and not in the business of guessing, that's up to you. The only way new BadClass[N];
leaks memory in itself is if it completes and you later toss out the only reference to it you're manually managing (array
).
An array being dynamically allocated, throwing within one of the constructors for elements therein, will (a) back out destructors in opposite order for elements already constructed,(b) free the allocated memory, and finally (c) officiate the actual throw to the nearest catch handler (or the default handler when there is none).
Because the throw happens, the assignment to the resulting array pointer never transpires, and therefore needs no delete
.
Best demonstrated by example:
#include <iostream>
struct A
static int count;
int n;
A() : n(++count)
std::cout << "constructing " << n << 'n';
if (count >= 5)
throw std::runtime_error("oops");
~A()
std::cout << "destroying " << n << 'n';
;
int A::count;
int main()
A *ar = nullptr;
try
ar = new A[10];
catch(std::exception const& ex)
std::cerr << ex.what() << 'n';
Output
constructing 1
constructing 2
constructing 3
constructing 4
constructing 5
destroying 4
destroying 3
destroying 2
destroying 1
oops
Note that because the construction of element '5' never completed, its destructor is not fired. However, members that were successfully constructed are destructed (not demonstrated in the example above, but a fun exercise if you're up for it).
All of that said, use smart pointers regardless.
That makes sense. Thanks!
– Galaxy
3 hours ago
2
@Galaxy Glad to help. Now. stop using manual memory management in C++ =P Stick with RAII idioms.
– WhozCraig
3 hours ago
That is a topic worthy for studying. Thanks again.
– Galaxy
3 hours ago
2
@Galaxy Do so. It will change the way you write C++ code. Believe me.
– WhozCraig
3 hours ago
add a comment |Â
up vote
2
down vote
In the following line of code:
array = new Badclass[10];
new Badclass[10]
is evaluated first. If that throws an exception then execution does not reach the assignment. array
retains its previous value which is nullptr
.
It has no effect to invoke delete on a nullptr
.
The question from the comments section:
Is this kind of behavior based on the same principle as stack unwinding?
The section on "Exception handling" in the standard helps us understand what happens when an exception is thrown at the time of allocation.
18 Exception handling [except]
...
18.2 Constructors and destructors [except.ctor]
1.As control passes from the point where an exception is thrown to a handler, destructors are invoked by a process, specified in this subclause, called stack unwinding.
...
3.If the initialization or destruction of an object other than by delegating constructor is terminated by an exception, the destructor is invoked for each of the object’s direct subobjects and, for a complete object, virtual base class subobjects, whose initialization has completed and whose destructor has not yet begun execution, except that in the case of destruction, the variant members of a union-like class are not destroyed. The subobjects are destroyed in the reverse order of the completion of their construction. Such destruction is sequenced before entering a handler of the function-try-block of the constructor or destructor, if any.
This is not part of stack unwinding because the constructed objects are not automatic objects. It should be paragraph 3 that applies.
– xskxzr
1 hour ago
Updated. Overlooked the "automatic" part. Thanks.
– P.W
1 hour ago
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
11
down vote
accepted
To answer the final question:
How would I go about solving this memory leak?
There is no memory leak. The leak would only happen if BadClass
itself dynamically allocated content and never freed it in its destructor. Since we're oblivious to your BadClass
implementation, and not in the business of guessing, that's up to you. The only way new BadClass[N];
leaks memory in itself is if it completes and you later toss out the only reference to it you're manually managing (array
).
An array being dynamically allocated, throwing within one of the constructors for elements therein, will (a) back out destructors in opposite order for elements already constructed,(b) free the allocated memory, and finally (c) officiate the actual throw to the nearest catch handler (or the default handler when there is none).
Because the throw happens, the assignment to the resulting array pointer never transpires, and therefore needs no delete
.
Best demonstrated by example:
#include <iostream>
struct A
static int count;
int n;
A() : n(++count)
std::cout << "constructing " << n << 'n';
if (count >= 5)
throw std::runtime_error("oops");
~A()
std::cout << "destroying " << n << 'n';
;
int A::count;
int main()
A *ar = nullptr;
try
ar = new A[10];
catch(std::exception const& ex)
std::cerr << ex.what() << 'n';
Output
constructing 1
constructing 2
constructing 3
constructing 4
constructing 5
destroying 4
destroying 3
destroying 2
destroying 1
oops
Note that because the construction of element '5' never completed, its destructor is not fired. However, members that were successfully constructed are destructed (not demonstrated in the example above, but a fun exercise if you're up for it).
All of that said, use smart pointers regardless.
That makes sense. Thanks!
– Galaxy
3 hours ago
2
@Galaxy Glad to help. Now. stop using manual memory management in C++ =P Stick with RAII idioms.
– WhozCraig
3 hours ago
That is a topic worthy for studying. Thanks again.
– Galaxy
3 hours ago
2
@Galaxy Do so. It will change the way you write C++ code. Believe me.
– WhozCraig
3 hours ago
add a comment |Â
up vote
11
down vote
accepted
To answer the final question:
How would I go about solving this memory leak?
There is no memory leak. The leak would only happen if BadClass
itself dynamically allocated content and never freed it in its destructor. Since we're oblivious to your BadClass
implementation, and not in the business of guessing, that's up to you. The only way new BadClass[N];
leaks memory in itself is if it completes and you later toss out the only reference to it you're manually managing (array
).
An array being dynamically allocated, throwing within one of the constructors for elements therein, will (a) back out destructors in opposite order for elements already constructed,(b) free the allocated memory, and finally (c) officiate the actual throw to the nearest catch handler (or the default handler when there is none).
Because the throw happens, the assignment to the resulting array pointer never transpires, and therefore needs no delete
.
Best demonstrated by example:
#include <iostream>
struct A
static int count;
int n;
A() : n(++count)
std::cout << "constructing " << n << 'n';
if (count >= 5)
throw std::runtime_error("oops");
~A()
std::cout << "destroying " << n << 'n';
;
int A::count;
int main()
A *ar = nullptr;
try
ar = new A[10];
catch(std::exception const& ex)
std::cerr << ex.what() << 'n';
Output
constructing 1
constructing 2
constructing 3
constructing 4
constructing 5
destroying 4
destroying 3
destroying 2
destroying 1
oops
Note that because the construction of element '5' never completed, its destructor is not fired. However, members that were successfully constructed are destructed (not demonstrated in the example above, but a fun exercise if you're up for it).
All of that said, use smart pointers regardless.
That makes sense. Thanks!
– Galaxy
3 hours ago
2
@Galaxy Glad to help. Now. stop using manual memory management in C++ =P Stick with RAII idioms.
– WhozCraig
3 hours ago
That is a topic worthy for studying. Thanks again.
– Galaxy
3 hours ago
2
@Galaxy Do so. It will change the way you write C++ code. Believe me.
– WhozCraig
3 hours ago
add a comment |Â
up vote
11
down vote
accepted
up vote
11
down vote
accepted
To answer the final question:
How would I go about solving this memory leak?
There is no memory leak. The leak would only happen if BadClass
itself dynamically allocated content and never freed it in its destructor. Since we're oblivious to your BadClass
implementation, and not in the business of guessing, that's up to you. The only way new BadClass[N];
leaks memory in itself is if it completes and you later toss out the only reference to it you're manually managing (array
).
An array being dynamically allocated, throwing within one of the constructors for elements therein, will (a) back out destructors in opposite order for elements already constructed,(b) free the allocated memory, and finally (c) officiate the actual throw to the nearest catch handler (or the default handler when there is none).
Because the throw happens, the assignment to the resulting array pointer never transpires, and therefore needs no delete
.
Best demonstrated by example:
#include <iostream>
struct A
static int count;
int n;
A() : n(++count)
std::cout << "constructing " << n << 'n';
if (count >= 5)
throw std::runtime_error("oops");
~A()
std::cout << "destroying " << n << 'n';
;
int A::count;
int main()
A *ar = nullptr;
try
ar = new A[10];
catch(std::exception const& ex)
std::cerr << ex.what() << 'n';
Output
constructing 1
constructing 2
constructing 3
constructing 4
constructing 5
destroying 4
destroying 3
destroying 2
destroying 1
oops
Note that because the construction of element '5' never completed, its destructor is not fired. However, members that were successfully constructed are destructed (not demonstrated in the example above, but a fun exercise if you're up for it).
All of that said, use smart pointers regardless.
To answer the final question:
How would I go about solving this memory leak?
There is no memory leak. The leak would only happen if BadClass
itself dynamically allocated content and never freed it in its destructor. Since we're oblivious to your BadClass
implementation, and not in the business of guessing, that's up to you. The only way new BadClass[N];
leaks memory in itself is if it completes and you later toss out the only reference to it you're manually managing (array
).
An array being dynamically allocated, throwing within one of the constructors for elements therein, will (a) back out destructors in opposite order for elements already constructed,(b) free the allocated memory, and finally (c) officiate the actual throw to the nearest catch handler (or the default handler when there is none).
Because the throw happens, the assignment to the resulting array pointer never transpires, and therefore needs no delete
.
Best demonstrated by example:
#include <iostream>
struct A
static int count;
int n;
A() : n(++count)
std::cout << "constructing " << n << 'n';
if (count >= 5)
throw std::runtime_error("oops");
~A()
std::cout << "destroying " << n << 'n';
;
int A::count;
int main()
A *ar = nullptr;
try
ar = new A[10];
catch(std::exception const& ex)
std::cerr << ex.what() << 'n';
Output
constructing 1
constructing 2
constructing 3
constructing 4
constructing 5
destroying 4
destroying 3
destroying 2
destroying 1
oops
Note that because the construction of element '5' never completed, its destructor is not fired. However, members that were successfully constructed are destructed (not demonstrated in the example above, but a fun exercise if you're up for it).
All of that said, use smart pointers regardless.
edited 3 hours ago
answered 3 hours ago


WhozCraig
50k855102
50k855102
That makes sense. Thanks!
– Galaxy
3 hours ago
2
@Galaxy Glad to help. Now. stop using manual memory management in C++ =P Stick with RAII idioms.
– WhozCraig
3 hours ago
That is a topic worthy for studying. Thanks again.
– Galaxy
3 hours ago
2
@Galaxy Do so. It will change the way you write C++ code. Believe me.
– WhozCraig
3 hours ago
add a comment |Â
That makes sense. Thanks!
– Galaxy
3 hours ago
2
@Galaxy Glad to help. Now. stop using manual memory management in C++ =P Stick with RAII idioms.
– WhozCraig
3 hours ago
That is a topic worthy for studying. Thanks again.
– Galaxy
3 hours ago
2
@Galaxy Do so. It will change the way you write C++ code. Believe me.
– WhozCraig
3 hours ago
That makes sense. Thanks!
– Galaxy
3 hours ago
That makes sense. Thanks!
– Galaxy
3 hours ago
2
2
@Galaxy Glad to help. Now. stop using manual memory management in C++ =P Stick with RAII idioms.
– WhozCraig
3 hours ago
@Galaxy Glad to help. Now. stop using manual memory management in C++ =P Stick with RAII idioms.
– WhozCraig
3 hours ago
That is a topic worthy for studying. Thanks again.
– Galaxy
3 hours ago
That is a topic worthy for studying. Thanks again.
– Galaxy
3 hours ago
2
2
@Galaxy Do so. It will change the way you write C++ code. Believe me.
– WhozCraig
3 hours ago
@Galaxy Do so. It will change the way you write C++ code. Believe me.
– WhozCraig
3 hours ago
add a comment |Â
up vote
2
down vote
In the following line of code:
array = new Badclass[10];
new Badclass[10]
is evaluated first. If that throws an exception then execution does not reach the assignment. array
retains its previous value which is nullptr
.
It has no effect to invoke delete on a nullptr
.
The question from the comments section:
Is this kind of behavior based on the same principle as stack unwinding?
The section on "Exception handling" in the standard helps us understand what happens when an exception is thrown at the time of allocation.
18 Exception handling [except]
...
18.2 Constructors and destructors [except.ctor]
1.As control passes from the point where an exception is thrown to a handler, destructors are invoked by a process, specified in this subclause, called stack unwinding.
...
3.If the initialization or destruction of an object other than by delegating constructor is terminated by an exception, the destructor is invoked for each of the object’s direct subobjects and, for a complete object, virtual base class subobjects, whose initialization has completed and whose destructor has not yet begun execution, except that in the case of destruction, the variant members of a union-like class are not destroyed. The subobjects are destroyed in the reverse order of the completion of their construction. Such destruction is sequenced before entering a handler of the function-try-block of the constructor or destructor, if any.
This is not part of stack unwinding because the constructed objects are not automatic objects. It should be paragraph 3 that applies.
– xskxzr
1 hour ago
Updated. Overlooked the "automatic" part. Thanks.
– P.W
1 hour ago
add a comment |Â
up vote
2
down vote
In the following line of code:
array = new Badclass[10];
new Badclass[10]
is evaluated first. If that throws an exception then execution does not reach the assignment. array
retains its previous value which is nullptr
.
It has no effect to invoke delete on a nullptr
.
The question from the comments section:
Is this kind of behavior based on the same principle as stack unwinding?
The section on "Exception handling" in the standard helps us understand what happens when an exception is thrown at the time of allocation.
18 Exception handling [except]
...
18.2 Constructors and destructors [except.ctor]
1.As control passes from the point where an exception is thrown to a handler, destructors are invoked by a process, specified in this subclause, called stack unwinding.
...
3.If the initialization or destruction of an object other than by delegating constructor is terminated by an exception, the destructor is invoked for each of the object’s direct subobjects and, for a complete object, virtual base class subobjects, whose initialization has completed and whose destructor has not yet begun execution, except that in the case of destruction, the variant members of a union-like class are not destroyed. The subobjects are destroyed in the reverse order of the completion of their construction. Such destruction is sequenced before entering a handler of the function-try-block of the constructor or destructor, if any.
This is not part of stack unwinding because the constructed objects are not automatic objects. It should be paragraph 3 that applies.
– xskxzr
1 hour ago
Updated. Overlooked the "automatic" part. Thanks.
– P.W
1 hour ago
add a comment |Â
up vote
2
down vote
up vote
2
down vote
In the following line of code:
array = new Badclass[10];
new Badclass[10]
is evaluated first. If that throws an exception then execution does not reach the assignment. array
retains its previous value which is nullptr
.
It has no effect to invoke delete on a nullptr
.
The question from the comments section:
Is this kind of behavior based on the same principle as stack unwinding?
The section on "Exception handling" in the standard helps us understand what happens when an exception is thrown at the time of allocation.
18 Exception handling [except]
...
18.2 Constructors and destructors [except.ctor]
1.As control passes from the point where an exception is thrown to a handler, destructors are invoked by a process, specified in this subclause, called stack unwinding.
...
3.If the initialization or destruction of an object other than by delegating constructor is terminated by an exception, the destructor is invoked for each of the object’s direct subobjects and, for a complete object, virtual base class subobjects, whose initialization has completed and whose destructor has not yet begun execution, except that in the case of destruction, the variant members of a union-like class are not destroyed. The subobjects are destroyed in the reverse order of the completion of their construction. Such destruction is sequenced before entering a handler of the function-try-block of the constructor or destructor, if any.
In the following line of code:
array = new Badclass[10];
new Badclass[10]
is evaluated first. If that throws an exception then execution does not reach the assignment. array
retains its previous value which is nullptr
.
It has no effect to invoke delete on a nullptr
.
The question from the comments section:
Is this kind of behavior based on the same principle as stack unwinding?
The section on "Exception handling" in the standard helps us understand what happens when an exception is thrown at the time of allocation.
18 Exception handling [except]
...
18.2 Constructors and destructors [except.ctor]
1.As control passes from the point where an exception is thrown to a handler, destructors are invoked by a process, specified in this subclause, called stack unwinding.
...
3.If the initialization or destruction of an object other than by delegating constructor is terminated by an exception, the destructor is invoked for each of the object’s direct subobjects and, for a complete object, virtual base class subobjects, whose initialization has completed and whose destructor has not yet begun execution, except that in the case of destruction, the variant members of a union-like class are not destroyed. The subobjects are destroyed in the reverse order of the completion of their construction. Such destruction is sequenced before entering a handler of the function-try-block of the constructor or destructor, if any.
edited 1 hour ago
answered 3 hours ago
P.W
5,2501329
5,2501329
This is not part of stack unwinding because the constructed objects are not automatic objects. It should be paragraph 3 that applies.
– xskxzr
1 hour ago
Updated. Overlooked the "automatic" part. Thanks.
– P.W
1 hour ago
add a comment |Â
This is not part of stack unwinding because the constructed objects are not automatic objects. It should be paragraph 3 that applies.
– xskxzr
1 hour ago
Updated. Overlooked the "automatic" part. Thanks.
– P.W
1 hour ago
This is not part of stack unwinding because the constructed objects are not automatic objects. It should be paragraph 3 that applies.
– xskxzr
1 hour ago
This is not part of stack unwinding because the constructed objects are not automatic objects. It should be paragraph 3 that applies.
– xskxzr
1 hour ago
Updated. Overlooked the "automatic" part. Thanks.
– P.W
1 hour ago
Updated. Overlooked the "automatic" part. Thanks.
– P.W
1 hour ago
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52829477%2fshould-you-free-an-array-if-allocating-that-array-threw-an-exception%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
If
new
throws,array
was never assigned, so there is nothing for you todelete
. So even if the exception comes from constructing one of the elements, the language guarantees memory is released.– BoBTFish
3 hours ago
@BoBTFish The thing is,
new
is not doing the throwing,Badclass::Badclass()
is!– Galaxy
3 hours ago
Nevertheless,
new
is the thing that callsBadclass::Badclass()
, sonew
never completes– Michael Veksler
3 hours ago
1
@Galaxy it doesn't matter. If the requested operation (allocate and construct this sequence of things) throws, everything done to that point related to those two activities is wound back. That includes both the allocation, and any objects that were successfully constructed (and array request of ten objects fulfilling five, then throwing, will fire destructors for the five that constructed successfully, in reverse order of construction, before relinquishing the memory itself and officiating the throw).
– WhozCraig
3 hours ago
1
Its based on success of requested operation. The request could not be fulfilled. Therefore, whatever could be is undone and the exception is thrown. That includes the destruction of already-constructed elements. Not that anyone would do any of this (you would likely just use a
std::vector
and be done with it, or have a darn good reason not to).– WhozCraig
3 hours ago