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;
}
Related
I have such class, where I create a move constructor
class Test
{
private:
int m_a;
public:
Test(int val) { m_a = val; }
Test (const Test &) {}
// move constructor
Test (Test && d)
{
std::cout << &m_a << std::endl; // Line X
std::cout << &d.m_a << std::endl;
}
void print()
{
std::cout << m_a << std::endl;
}
};
I also create a function to test move constructor
void fun(Test a)
{ return ; }
Than in main function I create 2 objects of class above and call function to test move constructor
int main()
{
Test a {50};
Test b {100};
fun(a);
fun(std::move(a));
fun(b);
fun(std::move(b));
return 0;
}
When I looked at the output, I was surprised, because the address of o m_a variable in line X has same address for both objects.
0x7ffc40d37bb4 // look at this
0x7ffc40d37bac
0x7ffc40d37bb4 // look at this
0x7ffc40d37bb0
How is it possible ? It's not static member, what is going on ? Compiler optimization or what ?
Each time fun(Test a) is invoked, an instance of Test is created on the stack. Each time fun() returns, the stack frame is freed.
So when invoked twice in a row, the chance is great that you get an instance of Test created at exact same location on the stack.
If you wanted to take Test by reference, it should be void fun(Test&& a).
How is it possible ?
The parameters of the separate invocations of fun don't have overlapping storage lifetimes. Hence, they can use the same storage.
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.
Here's a curious one. I have a class A. It has an item of class B, which I want to initialize in the constructor of A using an initializer list, like so:
class A {
public:
A(const B& b): mB(b) { };
private:
B mB;
};
Is there a way to catch exceptions that might be thrown by mB's copy-constructor while still using the initializer list method? Or would I have to initialize mB within the constructor's braces in order to have a try/catch?
Have a read of http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/)
Edit: After more digging, these are called "Function try blocks".
I confess I didn't know this either until I went looking. You learn something every day! I don't know if this is an indictment of how little I get to use C++ these days, my lack of C++ knowledge, or the often Byzantine features that litter the language. Ah well - I still like it :)
To ensure people don't have to jump to another site, the syntax of a function try block for constructors turns out to be:
C::C()
try : init1(), ..., initn()
{
// Constructor
}
catch(...)
{
// Handle exception
}
It's not particularly pretty:
A::A(const B& b) try : mB(b)
{
// constructor stuff
}
catch (/* exception type */)
{
// handle the exception
}
I know it has been awhile since this discussion started. But that try-and-catch construct mentioned by Adam is part of the C++ standard and is supported by Microsoft VC++ and GNU C++.
Here is the program that works. By the way the the catch generates automatically another exception to signal about the constructor failure.
#include <iostream>
#include <exception>
#include <string>
using namespace std;
class my_exception: public exception
{
string message;
public:
my_exception(const char* message1)
{
message = message1;
}
virtual const char* what() const throw()
{
cout << message << endl;
return message.c_str();
}
virtual ~my_exception() throw() {};
};
class E
{
public:
E(const char* message) { throw my_exception(message);}
};
class A
{
E p;
public:
A()
try :p("E failure")
{
cout << "A constructor" << endl;
}
catch (const exception& ex)
{
cout << "Inside A. Constructor failure: " << ex.what() << endl;
}
};
int main()
{
try
{
A z;
}
catch (const exception& ex)
{
cout << "In main. Constructor failure: " << ex.what() << endl;
}
return 0;
}
You could work with lazy initialization, though, that is hold a unique_ptr to Reader in MyClass and create it with new. That way, you do not even need the flag has_reader but you can just see if your unique_ptr is initial or not.
#include <iostream>
#include <memory>
using namespace std;
class MyOtherClass
{
public:
MyOtherClass()
{
throw std::runtime_error("not working");
}
};
class MyClass
{
public:
typedef std::unique_ptr<MyOtherClass> MyOtherClassPtr;
MyClass()
{
try
{
other = std::make_unique<MyOtherClass>();
}
catch(...)
{
cout << "initialization failed." << endl;
}
cout << "other is initialized: " << (other ? "yes" : "no");
}
private:
std::unique_ptr<MyOtherClass> other;
};
int main()
{
MyClass c;
return 0;
}
Of course, there are also solutions without using exceptions at all but I assumed that this is a prerequisite in your setting.
I don't see how you'd do that with initializer-list syntax, but I'm also a bit sceptical that you'll be able to do anything useful by catching the exception in your constructor. It depends on the design of the classes, obviously, but in what case are you going to fail to create "mB", and still have a useful "A" object?
You might as well let the exception percolate up, and handle it wherever the constructor for A is being called.
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.
Here's a curious one. I have a class A. It has an item of class B, which I want to initialize in the constructor of A using an initializer list, like so:
class A {
public:
A(const B& b): mB(b) { };
private:
B mB;
};
Is there a way to catch exceptions that might be thrown by mB's copy-constructor while still using the initializer list method? Or would I have to initialize mB within the constructor's braces in order to have a try/catch?
Have a read of http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/)
Edit: After more digging, these are called "Function try blocks".
I confess I didn't know this either until I went looking. You learn something every day! I don't know if this is an indictment of how little I get to use C++ these days, my lack of C++ knowledge, or the often Byzantine features that litter the language. Ah well - I still like it :)
To ensure people don't have to jump to another site, the syntax of a function try block for constructors turns out to be:
C::C()
try : init1(), ..., initn()
{
// Constructor
}
catch(...)
{
// Handle exception
}
It's not particularly pretty:
A::A(const B& b) try : mB(b)
{
// constructor stuff
}
catch (/* exception type */)
{
// handle the exception
}
I know it has been awhile since this discussion started. But that try-and-catch construct mentioned by Adam is part of the C++ standard and is supported by Microsoft VC++ and GNU C++.
Here is the program that works. By the way the the catch generates automatically another exception to signal about the constructor failure.
#include <iostream>
#include <exception>
#include <string>
using namespace std;
class my_exception: public exception
{
string message;
public:
my_exception(const char* message1)
{
message = message1;
}
virtual const char* what() const throw()
{
cout << message << endl;
return message.c_str();
}
virtual ~my_exception() throw() {};
};
class E
{
public:
E(const char* message) { throw my_exception(message);}
};
class A
{
E p;
public:
A()
try :p("E failure")
{
cout << "A constructor" << endl;
}
catch (const exception& ex)
{
cout << "Inside A. Constructor failure: " << ex.what() << endl;
}
};
int main()
{
try
{
A z;
}
catch (const exception& ex)
{
cout << "In main. Constructor failure: " << ex.what() << endl;
}
return 0;
}
You could work with lazy initialization, though, that is hold a unique_ptr to Reader in MyClass and create it with new. That way, you do not even need the flag has_reader but you can just see if your unique_ptr is initial or not.
#include <iostream>
#include <memory>
using namespace std;
class MyOtherClass
{
public:
MyOtherClass()
{
throw std::runtime_error("not working");
}
};
class MyClass
{
public:
typedef std::unique_ptr<MyOtherClass> MyOtherClassPtr;
MyClass()
{
try
{
other = std::make_unique<MyOtherClass>();
}
catch(...)
{
cout << "initialization failed." << endl;
}
cout << "other is initialized: " << (other ? "yes" : "no");
}
private:
std::unique_ptr<MyOtherClass> other;
};
int main()
{
MyClass c;
return 0;
}
Of course, there are also solutions without using exceptions at all but I assumed that this is a prerequisite in your setting.
I don't see how you'd do that with initializer-list syntax, but I'm also a bit sceptical that you'll be able to do anything useful by catching the exception in your constructor. It depends on the design of the classes, obviously, but in what case are you going to fail to create "mB", and still have a useful "A" object?
You might as well let the exception percolate up, and handle it wherever the constructor for A is being called.