Multiple calls to new in member initializer list okay?

  • Thread starter Niels Dekker - no reply address
  • Start date
N

Niels Dekker - no reply address

The book "C++ Coding Standards" by Herb Sutter and Andrei Alexandrescu
warns against potential memory leaks when having multiple calls to
operator new within a single statement. (Item 13, page 25.) These
leaks would still be there when wrapping the result of each "new" in a
temporary smart pointer object.

Is there a simular risk when having multiple calls to new in member
initializer list of a constructor? For example:

class Foo
{
// I might use either std::auto_ptr or boost::scoped_ptr.
const std::auto_ptr<A> m_a;
const std::auto_ptr<B> m_b;
public:
Foo() : m_a(new A), m_b(new B) {}
};

Is the compiler allowed to do:
1. allocate memory for m_a
2. allocate memory for m_b
3. call the constructor of A
4. call the constructor of B

And then, is it allowed to leave a memory leak when the constructor of A
throws an exception?

Kind regards,

Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
 
A

Alan Johnson

Niels said:
The book "C++ Coding Standards" by Herb Sutter and Andrei Alexandrescu
warns against potential memory leaks when having multiple calls to
operator new within a single statement. (Item 13, page 25.) These
leaks would still be there when wrapping the result of each "new" in a
temporary smart pointer object.

Is there a simular risk when having multiple calls to new in member
initializer list of a constructor? For example:

class Foo
{
// I might use either std::auto_ptr or boost::scoped_ptr.
const std::auto_ptr<A> m_a;
const std::auto_ptr<B> m_b;
public:
Foo() : m_a(new A), m_b(new B) {}
};

Is the compiler allowed to do:
1. allocate memory for m_a
2. allocate memory for m_b
3. call the constructor of A
4. call the constructor of B

And then, is it allowed to leave a memory leak when the constructor of A
throws an exception?

Kind regards,

Niels Dekker
http://www.xs4all.nl/~nd/dekkerware

This looks okay to me, the reason being that there is a sequence point
between "m_a(new A)" and "m_b(new B)" (that is, the first expression is
fully evaluated before the second is considered).

If the constructor of A throws an exception, "new A" will never
complete, so no memory will be leaked. If an exception is thrown after
m_a is fully constructed then the compiler will ensure that m_a is
properly destructed, so no leaks there either. The same argument
applies to B and m_b, so I would conclude that this usage is fine.

However, there is a similar usage that is not exception safe (just in
case you haven't encountered it):

Foo(std::auto_ptr a, std::auto_ptr b)
: m_a(a), m_b(b)
{}

// ...

// NOT EXCEPTION SAFE!!
Foo f(std::auto_ptr<A>(new A), std::auto_ptr<B>(new B)) ;

Here, there is NOT a sequence point between the two calls to new, so the
compiler may choose to execute "new A", then "new B", and then construct
the auto_ptr objects, but an exception thrown during "new B" would cause
the memory from "new A" to be leaked.

-Alan
 

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

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top