From: ychapran on
On Mar 3, 10:40 pm, MC <manan.cho...(a)gmail.com> wrote:
> Say I have the following classes
>
> class A{};
> class B{};
> class C{};
>
> class X{
> A* a;
> B* b;
> C* c;
> public:
> X() : a(new A), b(new B), c(new C) {}
>
> };
>
> Say now new fails while initializing C. Since X is not constructed
> completely it will not call its destructor and we will have a and b
> never destructed and hence a memory leak.
> What is the best way to avoid this problem.
>
> Should I never use new in the constructor?
>
> Thanks
>
> --
> [ Seehttp://www.gotw.ca/resources/clcm.htmfor info about ]
> [ comp.lang.c++.moderated. First time posters: Do this! ]


Actually there are 2 solutions:
- surround everything with try {} catch(), including calls of parent
classes constructors. See
http://stackoverflow.com/questions/697026/exception-handling-in-constructors-initializer-list

- use new that does not throw exceptions on failure. Then you can
check pointers in constructors body. See http://www.cplusplus.com/reference/std/new/nothrow/


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Daniel T. on
In article
<4b60b625-2b96-44ec-8c0a-ea8043c17b7a(a)a18g2000yqc.googlegroups.com>,
MC <manan.chopra(a)gmail.com> wrote:

> Say I have the following classes
>
> class A{};
> class B{};
> class C{};
>
> class X{
> A* a;
> B* b;
> C* c;
> public:
> X() : a(new A), b(new B), c(new C) {}
> };
>
> Say now new fails while initializing C. Since X is not constructed
> completely it will not call its destructor and we will have a and b
> never destructed and hence a memory leak.
> What is the best way to avoid this problem.
>
> Should I never use new in the constructor?

It's OK to use new in the constructor, but you have to make sure that it
will be deleted if something goes wrong. Using new in initializer lists
can be a problem. Although you can wrap the list in a try...catch block,
that doesn't help much when you have three objects getting newed like
you have. The obvious solution would be something like:

X::X(): a(0), b(0), c(0) {
try {
a = new A;
b = new B;
c = new C;
}
catch (...) {
delete a;
delete b;
delete c;
}
}

Depending on how you implement copy construction/assignment for the
class, another option may be to use auto_ptrs for the three objects.

class X {
auto_ptr<A> a;
auto_ptr<B> b;
auto_ptr<C> c;
public:
X() : a(new A), b(new B), c(new C) { }
};

If one of the news throws, the auto_ptrs that were initialized
successfully will delete what they own, but now X objects can't share
their object when copied.

Using a more sophisticated smart pointer can solve the sharing issue and
take care of destruction too!

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Nevin :-] Liber on
In article
<4b60b625-2b96-44ec-8c0a-ea8043c17b7a(a)a18g2000yqc.googlegroups.com>,
MC <manan.chopra(a)gmail.com> wrote:

> Say I have the following classes
>
> class A{};
> class B{};
> class C{};
>
> class X{
> A* a;
> B* b;
> C* c;
> public:
> X() : a(new A), b(new B), c(new C) {}
> };
>
> Say now new fails while initializing C. Since X is not constructed
> completely it will not call its destructor and we will have a and b
> never destructed and hence a memory leak.
> What is the best way to avoid this problem.

Store them in a smart pointer, such as std::auto_ptr, as in:

class X {
std::auto_ptr<A> a;
std::auto_ptr<B> b;
std::auto_ptr<C> c;
public:
X() : a(new A), b(new B), c(new C) {}
};

Some other candidates are tr1::unique_ptr, boost::scoped_ptr and
boost::shared_ptr, depending on what ownership semantics you want.

> Should I never use new in the constructor?

Using new is fine (assuming you have good reason not to store them by
value, such as polymorphism, lifetime issues, size issues, etc.); the
result should be stored in something that manages the lifetime of the
object, and not just a raw pointer.

--
Nevin ":-)" Liber <mailto:nevin(a)eviloverlord.com> 773 961-1620

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: jaybus56 on
On Mar 4, 3:07 am, peter koch larsen <peter.koch.lar...(a)gmail.com>
wrote:
> Not if you have more than one. You get around this problem by using
> auto_ptr:

agreed, but

> X()
> {
> auto_ptr<A> aa(new A);
> auto_ptr<B> ab(new B);
> a = aa.release();
> b = ab.release();
>
> }

I would do it this way because I prefer initializer lists (RAII):

class A{};
class B{};
class C{};

class X
{
auto_ptr<A> a;
auto_ptr<B> b;
auto_ptr<C> c;

public:
X() : a(new A), b(new B), c(new C) {}

// if it is necessary to keep the memory allocation:
~X()
{
a.release();
b.release();
c.release();
}
};


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Goran on
On Mar 3, 9:40 pm, MC <manan.cho...(a)gmail.com> wrote:
> Say I have the following classes
>
> class A{};
> class B{};
> class C{};
>
> class X{
> A* a;
> B* b;
> C* c;
> public:
> X() : a(new A), b(new B), c(new C) {}
>
> };
>
> Say now new fails while initializing C. Since X is not constructed
> completely it will not call its destructor and we will have a and b
> never destructed and hence a memory leak.
> What is the best way to avoid this problem.
>
> Should I never use new in the constructor?

You should, but not in the initializion list. peter koch larsen's
solution is correct.

Small addition: sometimes, there is a need to have (some of) these
pointers initialized sooner than at the end of the constructor, so you
do e.g.

class X
{
TYPE* a, b, c;
X()
{
auto_ptr<TYPE> Pa(new TYPE); // I tend to use "P" prefix for "smart
pointer".
a = Pa.get();
f_uses_a();
// Similar for b, c
Pa.release();
Pa.release();
Pc.release();
}

f_uses_a()
{
//...
a->method();
}
};

Goran.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]