exception from constructor

C

Christopher

There is a rumor around the office that it is unacceptable to throw an
exception from a constructor.
I have always thrown exceptions from constuctors. It is the only
method of handling errors!

Where in the world is this argument coming from?
Does it have any validity?

I seek knowledge o gurus of the C++
 
A

acehreli

There is a rumor around the office that it is unacceptable to throw an
exception from a constructor.

What do they recommend for when it's impossible to construct the
object?
I have always thrown exceptions from constuctors. It is the only
method of handling errors!

Of course. It is either an object or not.
Where in the world is this argument coming from?
Does it have any validity?

It comes from code that is not exception safe. In that case, any
exception can leak resources. Banning exceptions in constructors is an
attempt to get away from such problems.

Ali
 
M

Markus Moll

Hi
There is a rumor around the office that it is unacceptable to throw an
exception from a constructor.
I have always thrown exceptions from constuctors. It is the only
method of handling errors!

Where in the world is this argument coming from?
Does it have any validity?

To me, it sounds like they confuse constructors and destructors.
It is rarely a good idea to throw within a destructor.
http://new-brunswick.net/workshop/c++/faq/dtors.html#faq-11.13

Markus
 
J

James Kanze

What do they recommend for when it's impossible to construct
the object?

An assertion failure? Constructing the object with an invalid
state, which you test before each use?

In all but a few, very rare cases, of course, exceptions are
preferable to these alternatives.
 
J

Juha Nieminen

James said:
In all but a few, very rare cases, of course, exceptions are
preferable to these alternatives.

Of course if the constructor of a class can throw exceptions, some
care has to be taken when using such a class.

Example:

class A
{
int* table;
B b; // constructor can throw

// Disallow copying and assignment here, or whatever

public:
A():
table(new int[100]) // bad!
{}

~A() { delete[] table; }
};

The problem with the above code is that if the constructor of 'b'
throws an exception, the table is leaked.

You might try to avoid the problem with an A constructor like this:

A() try:
table(new int[100])
{}
catch(...)
{
delete[] table;
}

This is not ok, though. AFAIK trying to access a member variable from
a constructor catch block is undefined behavior. A practical case can be
constructed by switching the places of 'table' and 'b' inside A. In this
case 'b' is constructed first, and if it throws, the catch block will
attempt to delete an uninitialized pointer (which might not be null!),
which may cause a segmentation fault.

The proper way of implementing the constructor is:

A():
table(0) // ok
{
table = new int[100];
}

Now if b throws, nothing will have been allocated yet for the table,
so nothing leaks. (This is so even if we switch the order of 'table' and
'b'.)

Another possibility is to make 'table' a managed pointer (eg.
auto_ptr, a std::vector or a smart pointer), in which case it's ok to
initialize it in the initialization list.

The general rule is: Never allocate unmanaged memory in the
initialization list.
 
J

James Kanze

Of course if the constructor of a class can throw exceptions,
some care has to be taken when using such a class.

Any time something can throw exceptions, some care has to be
taken when using it. More to the point: any time an operation
can fail, some care has to be taken when using it.
class A
{
int* table;
B b; // constructor can throw
// Disallow copying and assignment here, or whatever
public:
A():
table(new int[100]) // bad!
{}
~A() { delete[] table; }
};
The problem with the above code is that if the constructor of
'b' throws an exception, the table is leaked.

But the issue above has nothing to do with constructors. You
get exactly the same problem if you write:

void
f()
{
int* table = new int[ 100 ] ;
g() ; // g() can throw...
}

Exception safety requires some thought. The alternative ways of
reporting errors do as well. The general rule is that if there
is any chance of the client code being able to handle an error
locally, you use a return value, rather than an exception.
Except when return values aren't possible: constructors and
overloaded operators, for example. In the case of constructors,
the exception has an additional advantage; the object we
couldn't construct isn't there, so it can't be used by error.
You might try to avoid the problem with an A constructor like this:
A() try:
table(new int[100])
{}
catch(...)
{
delete[] table;
}
This is not ok, though. AFAIK trying to access a member
variable from a constructor catch block is undefined behavior.
A practical case can be constructed by switching the places of
'table' and 'b' inside A. In this case 'b' is constructed
first, and if it throws, the catch block will attempt to
delete an uninitialized pointer (which might not be null!),
which may cause a segmentation fault.

I'm not sure, because I've never heard of anyone trying to do
this.

The standard way of avoiding the problem (in this case) is to
The proper way of implementing the constructor is:
A():
table(0) // ok
{
table = new int[100];
}
Now if b throws, nothing will have been allocated yet for the
table, so nothing leaks. (This is so even if we switch the
order of 'table' and 'b'.)

No, the proper way of implementing the constructor is, as I
said, to replace the int* with std::vector< int >. And more
generally, to ensure that any member of the class which needs
cleaning up is a proper class itself, with a destructor which
does the cleaning up.
 
A

Anarki

Of course if the constructor of a class can throw exceptions,
some care has to be taken when using such a class.

Any time something can throw exceptions, some care has to be
taken when using it.  More to the point: any time an operation
can fail, some care has to be taken when using it.
Example:
class A
{
    int* table;
    B b; // constructor can throw
    // Disallow copying and assignment here, or whatever
 public:
    A():
      table(new int[100]) // bad!
    {}
    ~A() { delete[] table; }
};
The problem with the above code is that if the constructor of
'b' throws an exception, the table is leaked.

But the issue above has nothing to do with constructors.  You
get exactly the same problem if you write:

    void
    f()
    {
        int* table = new int[ 100 ] ;
        g() ;     // g() can throw...
    }

Exception safety requires some thought.  The alternative ways of
reporting errors do as well.  The general rule is that if there
is any chance of the client code being able to handle an error
locally, you use a return value, rather than an exception.
Except when return values aren't possible: constructors and
overloaded operators, for example.  In the case of constructors,
the exception has an additional advantage; the object we
couldn't construct isn't there, so it can't be used by error.
You might try to avoid the problem with an A constructor like this:
    A() try:
      table(new int[100])
      {}
      catch(...)
      {
          delete[] table;
      }
This is not ok, though. AFAIK trying to access a member
variable from a constructor catch block is undefined behavior.
A practical case can be constructed by switching the places of
'table' and 'b' inside A. In this case 'b' is constructed
first, and if it throws, the catch block will attempt to
delete an uninitialized pointer (which might not be null!),
which may cause a segmentation fault.

I'm not sure, because I've never heard of anyone trying to do
this.

The standard way of avoiding the problem (in this case) is to
  The proper way of implementing the constructor is:
    A():
      table(0) // ok
    {
        table = new int[100];
    }
Now if b throws, nothing will have been allocated yet for the
table, so nothing leaks. (This is so even if we switch the
order of 'table' and 'b'.)

No, the proper way of implementing the constructor is, as I
said, to replace the int* with std::vector< int >.  And more
generally, to ensure that any member of the class which needs
cleaning up is a proper class itself, with a destructor which
does the cleaning up.

--
James Kanze (GABI Software)             email:[email protected]
Conseils en informatique orientée objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

@James

when is the construction of b done? after

table = new int[100];

or before that statement?
 
J

James Kanze

On Aug 1, 9:13 pm, James Kanze <[email protected]> wrote:

[...]
Example:
class A
{
int* table;
B b; // constructor can throw
// Disallow copying and assignment here, or whatever
public:
A():
table(new int[100]) // bad!
{}
~A() { delete[] table; }
};
The problem with the above code is that if the constructor of
'b' throws an exception, the table is leaked.

[...]
The proper way of implementing the constructor is:
A():
table(0) // ok
{
table = new int[100];
}
Now if b throws, nothing will have been allocated yet for the
table, so nothing leaks. (This is so even if we switch the
order of 'table' and 'b'.)

[You really have to learn to trim your citations. I'll
presume that your questions concern the above snippets,
since they're the only ones to which it seems to apply, but
I'm not sure, given the amount of additional material that
was present.]
when is the construction of b done? after
table = new int[100];
or before that statement?

Class members are initialized in the order of their declaration
in the class, using the initializations from the initializer
list, if present, and before entering the body of the
constructor. So in the second constructor above:

- table is initialized to a null pointer value,
- b is constructed,

and then we enter the constructor body, where the assignment to
table takes place.
 
J

Juha Nieminen

James said:
No, the proper way of implementing the constructor is, as I
said, to replace the int* with std::vector< int >.

The problem is if std::vector, or any other STL container, does not do
what you want, and you are creating your own data container.

If this is the case, at some point in your code you must explicitly
write the 'new', and you have to be careful that it doesn't leak in the
case of an exception.
 
J

James Kanze

The problem is if std::vector, or any other STL container,
does not do what you want,

Then you create one that does.
and you are creating your own data container.

Then you don't have a second element whose constructor might
throw.
If this is the case, at some point in your code you must
explicitly write the 'new', and you have to be careful that it
doesn't leak in the case of an exception.

There are obviously many cases where you need an explicit new.
That doesn't change anything; whether you use a standard
container, or write some container or smart pointer or whatever
of your own. The point is that any given class can only be
responsible for one resource. The principle of RAII is that the
responsibility for a resource is always in the hands of a single
class whose sole role is to be responsible for that resource.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,156
Latest member
KetoBurnSupplement
Top