I know Object *pObject=new Object contain two steps:
operator new to allocate memory
call object's constructor.
and call delete pObject:
call object's destruct;
operator delete to free memory.
But when new Object process, if the step 2 throw exception, if the operator delete be called to free memory by system?
No, the destructor is not called. As the object isn't constructed properly it would be unsafe to call the destructor. However if any member objects have been constructed fully then they are destructed (as the object is complete).
Some people recommend against throwing in constructors, I believe it is better than zombie states which is akin to error codes and makes verbose code. So long as you follow RAII you should be fine (each resource is managed by it's own object). Before you throw in the constructor make sure that you clean up anything you've half done, but again, if you're using RAII that should be nothing.
The following outputs "B":
#include <iostream>
struct B {
~B() { std::cout << "B" << std::endl; }
};
struct A {
A() : b() { throw(1); }
~A() { std::cout << "A" << std::endl; }
B b;
};
int main() {
try {
A *a = new A;
delete a;
} catch(int a) {}
}
Edit:
The above isn't what you asked, yes the delete operator is called, http://www.cplusplus.com/reference/new/operator%20delete[] says:
"These deallocation functions are called by delete-expressions and by new-expressions to deallocate memory after destructing (or failing to construct) objects with dynamic storage duration."
This could be tested by overriding the operator delete.
Yes, the operator delete will be called to release the memory allocated.
The program below can prove that:
#include <iostream>
using std::cout;
using std::endl;
class A {
public:
A() { cout << "A() at " << this << endl; throw 1; }
~A() { cout << "~A() at " << this << endl; }
};
int main(int argc, char *argv[]) {
int N = 3;
for (int i = 0; i < N; ++i) {
try {
new A;
} catch (int a) {
// pass
}
}
return 0;
}
Running this program on my system, I find that the result printed out are like this:
A() at 0x2170010
A() at 0x2170010
A() at 0x2170010
Obviously, the destructors are NOT call because NO
~A() at 0x2170010
lines are printed out.
And the operator delete are surely called because the addresses of the three objects are exactly the same.
Related
I want to create a vector of "Act" objects that contain pointers to either "Eat" or "Drink" dynamically allocated objects. The new objects are being emplaced like so:
action_vector.emplace_back(Act::BehaviorType::eat);
However, it is seg-faulting and I can't figure out why. I thought that emplace_back would implicitly call the move constructor, not the destructor, but for some reason it is, which (I think) is what is screwing everything up.
Is there any way to successfully create a vector of such objects?
Here is the rest of the code along with its output. Sorry if it's a little verbose, but basically it's just a strategy pattern.
#include <iostream>
#include <vector>
class IBehavior
{
public:
IBehavior() = default;
virtual ~IBehavior() = default;
virtual void execute() = 0;
};
class Drink : public IBehavior
{
public:
Drink(): IBehavior() {}
~Drink() {}
void execute() { std::cout << "Drinking" << std::endl; }
};
class Eat : public IBehavior
{
public:
Eat(): IBehavior() {}
~Eat() {}
void execute() { std::cout << "Eating" << std::endl; }
};
class Act
{
IBehavior * b;
public:
enum class BehaviorType { eat = 0, drink = 1 };
Act() = default;
~Act()
{
std::cout << "Calling the destructor" << std::endl;
delete b;
}
Act(BehaviorType b_type) { SetBehavior(b_type); }
Act(Act&& act)
{
std::cout << "Calling the move constructor" << std::endl;
this->b = act.b;
}
void SetBehavior(BehaviorType b_type)
{
if(b_type == BehaviorType::eat) b = new Eat();
if(b_type == BehaviorType::drink) b = new Drink();
}
void execute() { b->execute(); }
};
int main(int argc, char * argv[])
{
std::vector<Act> action_vector;
for(int i = 0; i < 10; ++i)
{
action_vector.emplace_back(Act::BehaviorType::eat);
action_vector[i].execute();
}
return 0;
}
output:
Eating
Calling the move constructor
Calling the destructor
Eating
Calling the move constructor
Calling the move constructor
Calling the destructor
Calling the destructor
Segmentation fault: 11
Your move constructor copies b, and destructor deletes b, so if you move construct an instance then the same pointer value will be deleted twice which has undefined behaviour.
General solution: Use a smart pointer.
Another bug: Default constructor leaves b uninitialised. When a default constructed object is destroyed, the uninitialised pointer is deleted and behaviour is undefined. Smart pointer fixes this also.
What happens, in the following code, if construction / destruction of some array element throws?
X* x = new X[10]; // (1)
delete[] x; // (2)
I know that memory leaks are prevented, but additionally:
Ad (1), are the previously constructed elements destructed? If yes, what happens if destructor throws in such a case?
Ad (2), are the not-yet-destructed elements destructed? If yes, what happens if destructor throws again?
Yes, if the constructor of x[5] throws, then the five array elements x[0]..x[4] already successfully constructed will be destroyed correctly.
Destructors should not throw. If a destructor does throw, this happens while the previous (constructor) exception is still being handled. As nested exceptions aren't supported, std::terminate is called immediately. This is why destructors shouldn't throw.
There are two mutually-exclusive options here:
If you reach label (2), the constructor didn't throw. That is, if x was successfully created, all ten elements were successfully constructed. In this case, yes, they all get deleted. No, your destructor still shouldn't throw.
If the constructor threw part-way through step (1), then the array x never really existed. The language tried to create it for you, failed, and threw an exception - so you don't reach (2) at all.
The key thing to understand is that x either exists - in a sane and predictable state - or it doesn't.
The language doesn't give you some un-usable half-initialized thing, if a constructor failed, because you couldn't do anything with it anyway. (You couldn't even safely delete it, because there would be no way to track which of the elements were constructed, and which were just random garbage).
It might help to consider the array as an object with ten data members. If you're constructing an instance of such a class, and one of the base-class or member constructors throws, all the previously-constructed bases and members are destroyed in exactly the same way and your object never starts existing.
We can test with the following code:
#include <iostream>
//`Basic` was borrowed from some general-purpose code I use for testing various issues
//relating to object construction/assignment
struct Basic {
Basic() {
std::cout << "Default-Constructor" << std::endl;
static int val = 0;
if(val++ == 5) throw std::runtime_error("Oops!");
}
Basic(Basic const&) { std::cout << "Copy-Constructor" << std::endl; }
Basic(Basic &&) { std::cout << "Move-Constructor" << std::endl; }
Basic & operator=(Basic const&) { std::cout << "Copy-Assignment" << std::endl; return *this; }
Basic & operator=(Basic &&) { std::cout << "Move-Assignment" << std::endl; return *this; }
~Basic() noexcept { std::cout << "Destructor" << std::endl; }
};
int main() {
Basic * ptrs = new Basic[10];
delete[] ptrs;
return 0;
}
This code yields the following output before crashing:
Default-Constructor
Default-Constructor
Default-Constructor
Default-Constructor
Default-Constructor
Default-Constructor
[std::runtime_error thrown and uncaught here]
Note that at no point were the Destructors called. This isn't necessarily a critical thing, since an uncaught exception will crash the program anyways. But if we catch the error, we see something reassuring:
int main() {
try {
Basic * ptrs = new Basic[10];
delete[] ptrs;
} catch (std::runtime_error const& e) {std::cerr << e.what() << std::endl;}
return 0;
}
The output changes to this:
Default-Constructor
Default-Constructor
Default-Constructor
Default-Constructor
Default-Constructor
Default-Constructor
Destructor
Destructor
Destructor
Destructor
Destructor
Oops!
So Destructors will be automatically called for fully constructed objects, even without an explicit delete[] call, because the new[] call has handling mechanisms to deal with this.
But you do have to worry about that sixth object: in our case, because Basic doesn't do any resource management (and a well-designed program wouldn't have Basic do resource management if its constructor could throw like this), we don't have to worry. But we might have to worry if our code looks like this instead:
#include <iostream>
struct Basic {
Basic() { std::cout << "Default-Constructor" << std::endl; }
Basic(Basic const&) { std::cout << "Copy-Constructor" << std::endl; }
Basic(Basic &&) { std::cout << "Move-Constructor" << std::endl; }
Basic & operator=(Basic const&) { std::cout << "Copy-Assignment" << std::endl; return *this; }
Basic & operator=(Basic &&) { std::cout << "Move-Assignment" << std::endl; return *this; }
~Basic() noexcept { std::cout << "Destructor" << std::endl; }
};
class Wrapper {
Basic * ptr;
public:
Wrapper() : ptr(new Basic) {
std::cout << "WRDefault-Constructor" << std::endl;
static int val = 0;
if(val++ == 5) throw std::runtime_error("Oops!");
}
Wrapper(Wrapper const&) = delete; //Disabling Copy/Move for simplicity
~Wrapper() noexcept { delete ptr; std::cout << "WRDestructor" << std::endl; }
};
int main() {
try {
Wrapper * ptrs = new Wrapper[10];
delete[] ptrs;
} catch (std::runtime_error const& e) {std::cout << e.what() << std::endl;}
return 0;
}
Here, we get this output:
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
WRDestructor
Oops!
The large block of Wrapper objects will not leak memory, but the sixth Wrapper object will leak a Basic object because it was not properly cleaned up!
Fortunately, as is usually the case with any resource-management scheme, all these problems go away if you use smart pointers:
#include <iostream>
#include<memory>
struct Basic {
Basic() { std::cout << "Default-Constructor" << std::endl; }
Basic(Basic const&) { std::cout << "Copy-Constructor" << std::endl; }
Basic(Basic &&) { std::cout << "Move-Constructor" << std::endl; }
Basic & operator=(Basic const&) { std::cout << "Copy-Assignment" << std::endl; return *this; }
Basic & operator=(Basic &&) { std::cout << "Move-Assignment" << std::endl; return *this; }
~Basic() noexcept { std::cout << "Destructor" << std::endl; }
};
class Wrapper {
std::unique_ptr<Basic> ptr;
public:
Wrapper() : ptr(new Basic) {
std::cout << "WRDefault-Constructor" << std::endl;
static int val = 0;
if(val++ == 5) throw std::runtime_error("Oops!");
}
//Wrapper(Wrapper const&) = delete; //Copy disabled by default, move enabled by default
~Wrapper() noexcept { std::cout << "WRDestructor" << std::endl; }
};
int main() {
try {
std::unique_ptr<Wrapper[]> ptrs{new Wrapper[10]}; //Or std::make_unique
} catch (std::runtime_error const& e) {std::cout << e.what() << std::endl;}
return 0;
}
And the output:
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
Oops!
Note that the number of calls to Destructor now match the number of calls to Default-Constructor, which tells us that the Basic objects are now getting properly cleaned up. And because the resource management that Wrapper was doing has been delegated to the unique_ptr object, the fact that the sixth Wrapper object doesn't have its deleter called is no longer a problem.
Now, a lot of this involves strawmanned code: no reasonable programmer would ever have a resource manager throw without proper handling code, even if it were made "safe" by use of smart-pointers. But some programmers just aren't reasonable, and even if they are, it's possible you might come across a weird, exotic scenario where you have to write code like this. The lesson, then, as far as I'm concerned, is to always use smart pointers and other STL objects to manage dynamic memory. Don't try to roll your own. It'll save you headaches exactly like this when trying to debug things.
I am having a trouble of putting multiple class objects as member of another class. To be more specific: lets assume we have 2 classes, A and B and class A is nested. I want the main function to have an array with 3 objects of class B. The first object will have 2 objects of class A, the second object will have 5 objects of class A and the third object will have 7 objects of class A. How can i do that? Below is one of my thoughts:
Class A{
private:
int variable;
public:
A(){
cout<< A created! <<endl;
}
~A(){
cout<< A destructed! <<endl;
}
};
Class B{
private:
A array[6]; //It will always create 6 elements of class A...
public:
B(){
cout<< B created! <<endl;
}
~B(){
cout<< B destructed! <<endl;
}
};
int main(){
B* array[3];
for (i = 0 ; i <= 2 ; i++)
{
array[i] = new B(); //Every B element in array have 6 elements of class A
}
}
Thanks in advance!
If you can't use vectors.. (which you should).. here is a working example that shows what you want to do with arrays and manual memory management. https://ideone.com/KihmON
Note: there is no error handling in here. If this was your program it's very unlikely new will ever fail, but for larger objects it can. If you thrown an error in main before your delete statements, those objects will never get deleted. That is why vector is preferred, in the case of errors, it will get cleaned up when it leaves scope no matter what.
#include <iostream>
class A
{
private:
int variable;
public:
A()
{
std::cout << "A created!" << std::endl;
}
~A()
{
std::cout << "A destructed!" << std::endl;
}
};
class B
{
private:
size_t arrayOnHeapSize; // size of array on heap
A* arrayOnHeap; // memory must be allocated before this is used.
public:
B(size_t arrSize) :
arrayOnHeapSize(arrSize)
{
arrayOnHeap = new A[arrSize]; // must deallocate memory manually, use "delete[]" arrays of objects
std::cout<< "B created with size" << arrSize << '!' << std::endl;
}
~B()
{
delete[] arrayOnHeap; // must deallocate memory manually
std::cout << "B destructed! Wouldn't have had to do memory management manually if I had used a vector!" << std::endl;
}
B(const B&) = delete; // If you need to make a copy, you'll have to make a copy constructor that performs a deep copy or adds some (ugly) reference counting logic. Could also opt to implement a move constructor. If you copied this as is, the pointer will get copied, one B will get destructed freeing the memory, then the other B will have a dangling pointer and try to free that upon destruction. No good.
};
int main()
{
B* arrayOfB[3];
arrayOfB[0] = new B(2);
arrayOfB[0] = new B(5);
arrayOfB[0] = new B(7);
delete arrayOfB[0]; // must deallocate manually, using "delete" instead of "delete[]" because these are each 1 object, not arrays.
delete arrayOfB[1];
delete arrayOfB[2];
// Don't need to delete arrayOfB as it is a local on the stack and will be taken care of as the function exits.
}
You can make B a parameterised type (I think that's the correct term):
template<int a>
class B {
A array[a];
};
int main() {
B<2> b1;
B<5> b2;
B<7> b3;
}
However they can't be in an array as B<2> is a different type to B<7> etc.
Suppose we have a constructor which may throw exceptions.
class A{
public:
A(); // may throw exceptions
};
And we can use this way to catch the exceptions:
try{
A a;
// do somethings to a, and I have to put everything about a here
}catch(...){
// handle exceptions
}
So my question is how to avoid putting everything in the try-catch block, without using a pointer.
You could define a creation function that handles the exception for you, with a sensible default value to return in case of an exception, for example:
struct A
{
A() : data("Default")
{
std::cout << "In A()" << std::endl;
}
A(const A& other) : data(other.data)
{
std::cout << "In A(A)" << std::endl;
}
A(bool param)
{
std::cout << "In A(bool)" << std::endl;
if(param)
throw std::runtime_error("Failed");
data = "Hello";
}
std::string data;
};
A createA(bool param, A& def_a)
try
{
return A(param);
}
catch (...) {
//...
return def_a;
}
Then you can initiate your actual A with the return value of this function. Due to RVO, no copy will be performed if the creation is successful, only if it fails (as it will have to then copy the default value):
int main(int argc, char**args)
{
A defA;
A a1 = createA(true, defA);
A a2 = createA(false, defA);
std::cout << "A1: " << a1.data << std::endl;
std::cout << "A2: " << a2.data << std::endl;
return 0;
}
The output of this is:
In A()
In A(bool)
In A(A)
In A(bool)
A1: Default
A2: Hello
The first constructor is the default value. Then you can see after the first A(bool) call (which throws), a copy constructor call is made to return the default value. The second call, which doesn't fail, has no copy constructor call (due to RVO). After this you end up with a default A and a successfully created A which you can use thereafter.
Of course, if the copy constructor can also throw, then you might have an exception escape createA - if this is the case you would have to modify this design somewhat.
One possible approach is to use a sentry.
class sentry {
public:
bool exception_thrown=true;
void constructed()
{
exception_thrown=false;
}
~sentry()
{
if (exception_thrown)
{
// Whatever you want to do
}
}
};
Then:
sentry a_sentry;
A a;
a_sentry.constructed();
In the sentry's destructor, if exception_thrown is set, it could only be because an exception was thrown in A's constructor, because the flag gets cleared immediately after A gets fully constructed. So, put the cleanup code in the destructor. One thing you have to be careful with this approach is that the destructor itself cannot throw an exception of its own.
You can then also do things like:
class A_with_sentry : public sentry, public A {
public:
A_with_sentry()
{
constructed();
}
};
Then just declare:
A_with_sentry a;
Then, go a step further, and make this a template function, have the constructor perfect-forward its variadic parameters to the sentried object's constructor, etc...
There is other way but not recommended because you need to deal with pointers.
A* a=nullptr;
try {
a = new A();
}
catch(...){
}
if(a){
//do somethings to a, and I have to put everything about a here
delete a;
}
So we have a constructor that can throw an exception depending on the arguments passed to it, but we do not know how to delete the object if this occurs. Important part of the code:
try
{
GameBase *gameptr = GameBase::getGame(argc, argv);
if (gameptr == 0)
{
std::cout << "Correct usage: " << argv[PROGRAM_NAME] << " " << "TicTacToe" << std::endl;
return NO_GAME;
}
else
{
gameptr->play();
}
delete gameptr;
}
catch (error e)
{
if (e == INVALID_DIMENSION)
{
std::cout << "Win condition is larger than the length of the board." << std::endl;
return e;
}
}
catch (...)
{
std::cout << "An exception was caught (probably bad_alloc from new operator)" << std::endl;
return GENERIC_ERROR;
}
In the third line, GameBase::getGame() calls the constructor for one of the games derived from GameBase and returns a pointer to that game, and these constructors can throw exceptions. The question is, how can we then delete the (partial?) object pointed to by gameptr if this occurs? If an exception is thrown, we will exit the scope of gameptr because we leave the try block and cannot call delete gameptr.
To assess the exception safety, you need to provide more detail of the construction of the object in GameBase::getGame.
The rule is through, that if a constructor throws, the object is not created, hence the destructor is not called. Associated memory allocations are also deallocated (i.e. the memory for the object itself).
The issue then becomes, how was the memory allocated to begin with? If it was with a new GameBase(...), then there is no need to deallocate or delete the resultant pointer - the memory is deallocated by the runtime.
For clarity on what happens to the member variables that are already constructed; they are destructed on the exception of the "parent" object. Consider the sample code;
#include <iostream>
using namespace std;
struct M {
M() { cout << "M ctor" << endl; }
~M() { cout << "M dtor" << endl; }
};
struct C {
M m_;
C() { cout << "C ctor" << endl; throw exception(); }
~C() { cout << "C dtor" << endl; }
};
auto main() -> int {
try {
C c;
}
catch (exception& e) {
cout << e.what() << endl;
}
}
The output is;
M ctor
C ctor
M dtor
std::exception
If the M m_ member is to be dynamically allocated, favour a unique_ptr or a shared_ptr over a naked pointer, and allow the smart pointers to manage the object for you; as follows;
#include <iostream>
#include <memory>
using namespace std;
struct M {
M() { cout << "M ctor" << endl; }
~M() { cout << "M dtor" << endl; }
};
struct C {
unique_ptr<M> m_;
C() : m_(new M()) { cout << "C ctor" << endl; throw exception(); }
~C() { cout << "C dtor" << endl; }
};
The output here mirrors the output above.
When you write Foo* result = new Foo(), the compiler translates this to the equivalent of this code:
void* temp = operator new(sizeof(Foo)); // allocate raw memory
try {
Foo* temp2 = new (temp) Foo(); // call constructor
result = temp2;
} catch (...) {
operator delete(temp); // constructor threw, deallocate memory
throw;
}
So you don't need to worry about the allocated memory if the constructor throws. Note, however, that this does not apply to extra memory allocated within the constructor. Destructors are only called for objects whose constructor finished, so you should get all your allocations into small wrapper objects (smart pointers) immediately.
If you throw in a constructor, the object is not constructed and thus, you are responsible for the deletion of allocated resources. This goes even further! Consider this Code
int a = function(new A, new A);
It is up to the compiler in which ordering is the A allocated AND constructed. You might end up with an memory leak, if your A constructor can throw!
Edit:
Use instead
try{
auto first = std::make_unique<A>();
auto second = std::make_unique<A>();
int a = function(*first, *second);
...