Catching exceptions from a constructor's initializer list

C++Exception

C++ Problem Overview


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?

C++ Solutions


Solution 1 - C++

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
}

Solution 2 - C++

It's not particularly pretty:

A::A(const B& b) try : mB(b) 
{ 
    // constructor stuff
}
catch (/* exception type */) 
{
    // handle the exception
}

Solution 3 - C++

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;
}

Solution 4 - C++

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.

Solution 5 - C++

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHead GeekView Question on Stackoverflow
Solution 1 - C++Adam WrightView Answer on Stackoverflow
Solution 2 - C++Michael BurrView Answer on Stackoverflow
Solution 3 - C++Mikhail SemenovView Answer on Stackoverflow
Solution 4 - C++IceFireView Answer on Stackoverflow
Solution 5 - C++Mark BesseyView Answer on Stackoverflow