8

This compiles, but I've never seen it in any other code. Is it safe?

Testclass():sources(new int[32]){}

Instead of:

Testclass(){
    sources = new int[32];
}
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
johnbakers
  • 23,563
  • 21
  • 114
  • 241
  • 2
    What's the difference between a pointer being initialized with `new` and any other member being initialized otherwise? – chris Feb 04 '13 at 06:55
  • @SebbyJohanns better way is to use vector, which is `"safer"` – billz Feb 04 '13 at 07:01

2 Answers2

14

Use:

Testclass():sources(new int[32]){}

This is using member-initialization-list which is the preferred way to initialize members.

By "safe" or "okay" you probably meant, whether it is exception-safe? What if new throws the bad_alloc exception?

Well, in that case, the destructor will not be called, because the object is not fully-constructed, as constructor-body is not executed. There may be a resource leak if you've acquired any resource in the initialization list.

Consider this,

class X
{
    int  *ints;  // Order of declaration matters!
    Huge *huges; // It ensures that huges will be initialized after ints

    X() : ints(new int[32]), huges(new Huge[10000]) {}
};

If new Huge[10000] throws an exception, the memory allocated toints will leak!

In such cases, function-try-block can be useful. See these:

If you think about this problem of exception-safety, you will soon realize that if a class manages just one resource, then the life will be easier. If a single class manages more than one resource, then you wouldn't be able to decide which one threw an exception in the member-initialization-list, and consequently, you wouldn't be able to decide which one is to be deallocated in the catch block of function-try-block. A resource leak is destined.

However, if a class needs more than one resource, then first you encapsulate each of the different type of resource in a class, and declare objects of these resource-managing class as a member of your class.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Nawaz
  • 341,464
  • 111
  • 648
  • 831
  • I know that it is. The question is, using `new` in this list is okay? – johnbakers Feb 04 '13 at 06:56
  • @SebbyJohanns: *"okay"* in what sense? – Nawaz Feb 04 '13 at 06:57
  • Well I have read that it is wise practice to initialize your ivars as much as possible in the member initializer, yet in all the code I see, pointers using `new` are defined only in the body of the constructor, not in this list, so I wondered if there was a good reason for this, i.e. is doing it "okay" (safe, etc) – johnbakers Feb 04 '13 at 06:58
  • 1
    @SebbyJohanns: Well, by "safe" or "okay" you probably meant, whether it is exception-safe? What if `new` throws bad_alloc? Well, in that case, the destructor will not be called. – Nawaz Feb 04 '13 at 07:00
  • 2
    Ah, function-try-blocks. I've never had to use one, but I can imagine the confusion that comes out of those who haven't had the luxury of discovering them in a "Hidden Features of C++" question on SO :) – chris Feb 04 '13 at 07:10
  • `a class must not manage more than ONE resource` ?!?!? One of the great benefits of aggregates is precisely this - combining the management of more than one resource into a single object. – Lightness Races in Orbit Feb 04 '13 at 07:38
  • @SebbyJohanns: Real code doesn't use raw pointers anyway – Lightness Races in Orbit Feb 04 '13 at 07:39
  • @LightnessRacesinOrbit: Isn't it better if the aggregate combines more than one resource-managing objects instead of resource themselves? – Nawaz Feb 04 '13 at 07:44
  • @Nawaz: Oh that, well, yes I suppose. Maybe. Sometimes not, if you need to be conservative about overhead and the two resources are to be managed in concert. There are also arguments about nesting too many damn layers for no real reason – Lightness Races in Orbit Feb 04 '13 at 07:51
  • @LightnessRacesinOrbit: I agree. But that is rare. I rephrased my statement, so the tone is suggestive now. – Nawaz Feb 04 '13 at 07:52
1

It's okay if you use the weird C++ syntax for using a try/catch block in a constructor's initializer list:

class C {
    int *n;
public:
    C();
};

C::C()
try : n(new int[100])
{
  // do stuff here
}
catch(...)
{
  // handle exceptions
}

int main()
{
    C c; // Should be safe...
}
Moonshine
  • 21
  • 4
  • What if there are more than one pointer members which are to be allocated in the mem-init-list? What would you handle in the `catch` block? and how? – Nawaz Feb 04 '13 at 10:01
  • I don't know of a way to test which object failed to allocate in that case. If you need that much control, as far as I know you're pretty much stuck writing an init() which can test each allocation individually for exceptions. I suppose if you HAD to use the initializer list, you could make wrapper classes for all the members you're allocating and make them throw individual, custom exceptions.. then test for each one. That'd be just getting ridiculous though. – Moonshine Feb 05 '13 at 21:49