Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I not specify the constructor when newing an array?

Updates:

The link above and the answers below didn't answer WHY this feature is not standardized. That is just what makes me wonder. Please consider the performance issue between std::vector<A> arr(8, 7); and new A[8](7);:

If we use std::vector<A> arr(8, 7); it may (not must) be implemented as follows:

this->internal_buf = new A[8]; // Call default constructor A() 8 times!
for (auto i = 0; i < 8; ++i)
{
    this->internal_buf[i] = A(7); // Call constructor A(7) 8 times AGAIN!!!
}

If C++ supports new A[8](7); It can be implemented as follows:

A* arr = (A*)malloc(sizeof(A) * 8 + extra_size);

for (auto i = 0; i < 8; ++i)
{
    new (&arr[i]) A(7); // Call constructor A(7) 8 times ONLY.
}

Compare the two methods, it is obvious that new A[8](7); is FASTER than std::vector<A> arr(8, 7);

Besides, I also feel new A[8](7); is more succinct and more expressive than std::vector<A> arr(8, 7);

Anyway, I think C++ should give programmers another alternative tool such as this feature. Because one of the C++ philosophies is "Give you as many tools as possible, but you don't have to pay for what you don't need."

The following is the original post:

struct A
{
    int n;
    A() : n() {}
    A(int n) : n(n) {}
};

int main()
{
    new A[8];    // OK
    new A[8]();  // OK
    new A[8](7); // Error
}

Why can I not specify the constructor when newing an array?

Why does the C++ standard not support such a handy feature? What's the rationale?

like image 847
xmllmx Avatar asked Sep 16 '13 16:09

xmllmx


2 Answers

Why does the C++ standard not support such a handy feature? What's the rationale?

Because there are better alternatives that can replace builtin arrays in (almost) all use cases (yes, even for passing to C-APIs): std::vector for dynamic arrays (allocated with new) and std::array for stack-allocated ones.

With std::vector, you could use std::vector<A> arr(8, 7) (as WhozCraig commented) which creates a vector of 8 elements, initializing each of them with 7. Leaving out the second argument will use their default constructors (builtin types are initialized with 0 or false).

Besides this and other convenience features (notably automatic resizing / push_back()), the biggest advantage of std::vector over creating arrays with new is that it adheres to RAII, meaning that it will automatically delete[] it's objects/memory as soon as it leaves scope -- no matter if by "falling off the function's end", a return statement, break, continue, goto or throwing an exception.

like image 159
Oberon Avatar answered Oct 13 '22 00:10

Oberon


Vector is not implemented like this:

this->internal_buf = new A[8]; // Call default constructor A() 8 times!
for (auto i = 0; i < 8; ++i)
{
    this->internal_buf[i] = A(7); // Call constructor A(7) 8 times AGAIN!!!
}

It is implemented roughly like:

typedef UninitializedBackingStoreForA B;

this->internal_buf = new B[8];
for (auto i = 0; i < 8; i++)
    new (&B[i]) A(7);

That is it uses uninitialized storage and placement new to construct elements.

So your intuition is wrong, vector already has the performance you seek. The constructor is called once per element, and a default constructor is not required.

like image 45
Andrew Tomazos Avatar answered Oct 13 '22 01:10

Andrew Tomazos