views:

234

answers:

6

Which is the right way to allocate memory via new in the C++ constructor. First way in the argument list:

class Boda {
    int *memory;
    public:
        Boda(int length) : memory(new int [length]) {}
        ~Boda() { delete [] memory; }
};

or in the body of constructor:

class Boda {
    int *memory;
    public:
        Boda(int length) {
            memory = new int [length];
        }
        ~Boda() { delete [] memory; }
};

Thanks, Boda Cydo.

A: 

If you want to catch memory allocation errors (which you probably should) then you'll have to make the call to new in the body of the constructor.

njplumridge
Not true, actually. (And in both cases. If memory allocation fails, this constructor can't do a thing about it and so should *not* catch the exception. And you can use a function try block to get the whole thing in a try-catch block.)
GMan
+1  A: 

I would say both are equivalent in the effect they produce and both are "the right way". I prefer initializer lists but I would go with the second variant just to be able to test for invalid length argument before trying to allocate the memory.

celavek
They are equivalent for simple types, but in general they're not. Using the initialiser list will construct the object from the arguments; using the constructor body will default-construct the object and then reassign it. This might be less efficient, and will only work if the object is default-constructible and assignable.
Mike Seymour
+2  A: 

The problem is more general. See C++ FAQ Lite: [10.6] Should my constructors use "initialization lists" or "assignment"?

adf88
+1 for the link to the FAQ. FAQs should always be read or searched first.
Thomas Matthews
+2  A: 

You should use resource management classes that will handle it for you. Else, you run into some serious problems with exception safety, aside from needlessly duplicating existing logic and maintenance of copy/assignment operators.

DeadMG
+3  A: 

I think the simplest way to do this would be to use a boost scoped array and let someone else's well tested library code handle it all for you.

So:

class Boda {
    boost::scoped_array<int> memory;
    public:
        Boda(int length) : memory(new int [length]) {}
       ~Boda() {}
};

Moreover, scoped arrays cannot be copied - so you avoid the nasty copy constructor deallocation issue mentioned in another answer.

Alex
Actually, you should use `boost::scoped_array`.
Pedro d'Aquino
Thanks. Just spotted it was an array alloc. Teach me to read the question properly.
Alex
`delete` is a code smell: it should only appear in dedicated resource management classes... and those are often already properly coded in available libraries (STL / Boost for example).
Matthieu M.
A: 

memory member variable is a pointer, if you allocate it in initialization list and it fails, your class is not initialized and you don't need to free it later (thanks to RAII design pattern which is used by C++ for class initialization). If you allocate its memory inside the constructor's body, similar behavior will happens.

But if you want to handle something, then allocate its memory in the constructor's body. Check something or try/catch it or print some useful messages, but at least, you have to throw another exception, because your class initialization is broken.

I think memory allocation in the constructor's body is more readable than the other one.

PC2st