2

In my course notes these two examples are given. Apparently the first one is not allowed, is there a technical reason why I can't allocate on stack? Or is this the C++ standard?

   // Constructor may force dynamic allocation when initializating an array of objects.

   Complex ac[10];             // complex array initialized to 0.0
    for ( int i = 0; i < 10; i += 1 ) {
         ac[i] = (Complex){ i, 2.0 } // disallowed
    }


    // MUST USE DYNAMIC ALLOCATION
    Complex *ap[10];            // array of complex pointers
    for ( int i = 0; i < 10; i += 1 ) {
         ap[i] = new Complex( i, 2.0 ); // allowed
    }
2
  • 6
    I hate it when course notes contain obvious bullsh*t. >:-( Commented Jul 18, 2011 at 13:37
  • 1
    You should never use the second way, because it will leak if the new throws. Ignore your corse notes (they were obviously written by somebody without a clue), and read up about RAII. It is the most important thing to know about C++. Commented Jul 18, 2011 at 13:41

5 Answers 5

7

The first one is not valid syntax. But assuming your Complex class has a public copy-assignment operator (the implicit one should probably be fine), then the following should be fine:

Complex ac[10];             // complex array initialized to 0.0
for ( int i = 0; i < 10; i += 1 ) {
     ac[i] = Complex( i, 2.0 );
}
Sign up to request clarification or add additional context in comments.

5 Comments

You're also assuming a public default constructor.
@Mike: True. But that assumption is based on the fact that the OP has only commented one line in his code snippet as "disallowed".
Problem is that implicit copy-assignment could lead to unwanted behavior because it only achieves flat copies. Of course one would have its own copy-assignment operator if the class needs deep copies but beginners could miss that.
@Nobody: Indeed. But I think that's way outside the scope of this question.
@Oli Charlesworth: Just wanted to point this out as I had a similar problem in my early days. I think it could also be the reason why they did not use it in the course.
6

Apparently the first one is not allowed

True, but only because it uses a wrong syntax. The following works:

ac[i] = Complex(i, 2.0);

So the claim is in fact wrong (assuming that Complex can be assigned to, which it by default can) – no dynamic allocation is needed.

5 Comments

@Mark It doesn’t really exist in the current C++. It’s just nonsense.
I think he intends for it to be similar to Complex x={i, 2.0}, which is a C-style way for initializing elements of a struct.
the course note also had the line, "Constructor may force dynamic allocation when initializating an array of objects." on top of the two examples. Do you know what they mean?
@Mark: (Complex){i , 2.0} is a C99 compound literal. Some C++ compilers might permit them as an extension.
@Mark: When you create an array of objects the default constructor is called on each object in the array to initialize it to ensure having valid objects. If you only declare an array of pointers the only thing to initialize would be the pointers.
2

The following is perfectly allowed -- you just had the wrong syntax. You can't cast initializer lists, but you can call constructors as though they are functions.

Complex ac[10];  // calls default constructor for each element
for ( int i = 0; i < 10; i += 1 ) {
     ac[i] = Complex(i, 2.0);  // constructs a temporary,
                               // then uses the assignment operator
}

6 Comments

Is it technically possible to create a Complex constructor that takes a std::initializer_list parameter? Would automatic conversion take care of this case for you? I don't have a standards-compliant compiler to test this on.
@MadKeithV: I honstly don't know. But even if you can, that only works in C++0x. This answer works in C++98 as well.
I'm not suggesting it as a serious answer (or I would have created such an answer), just intrigued by the possibility.
@MadKeithV: In C++11 you can.
@MadKeithV Complex::Complex(std::initializer_list<double>); and then ac[i] = { i, 2.0 };. But the constructor has to be non-explicit and it's weird to use an std::initializer_list for a fixed number of arguments. Note that the C++0x rules do allow for ac[i] = { i, 2.0 }; iff there is an agreeable converting constructor (i.e. non-explicit); e.g. one that accepts (double, double).
|
1

You may of course provide all the values in an initializer-list, like

Complex ac[] = { Complex(0, 2.0), Complex(1, 2.0), /* and so on */ };

but this gets very unwieldy very quickly as the size increases. So it's natural to want to use a loop.

While it's not impossible to independently initialize elements in an automatic (which usually equates to "on stack") buffer, it's not at all easy.

The problem is that defining an array causes the constructor to be called immediately. You'd have to define a char array (which has no constructor), and then construct and destroy the elements manually (using placement new and explicit destructor calls). This isn't so hard unless you want exception safety, in which case the corner cases are very difficult to handle.

If you're allowed to default-construct and then reassign the elements, it's easy, and covered by the other answers. If Complex has a working assignment operator, you should do this.

3 Comments

This use of a stack allocated char array and placement new is undefined. The char array is not guaranteed to be correctly aligned for the Complex type.
@Mankarse: That doesn't prevent using an automatic char array, it just means some additional care is required.
Agreed. Alignment is implementation defined. I just thought I would mention it in case anyone was going to actually try to follow your suggestion.
0

There is no such rule that constructor must have dynamic allocation for array.

ac[i] = Complex( i, 2.0 );

is valid. In fact you should avoid dynamic arrays, as much as you can.

2 Comments

It’s not even a dynamic array, it’s a static array of pointers (that should be avoided).
@Konrad, he cannot avoid learning pointers, as it's in their exams. But yes, pointers also should be avoided.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.