为什么新建数组时不能指定构造函数?

时间:2013-09-16 16:48:55

标签: c++ arrays c++11 constructor initialization

更新

上面的链接和下面的答案没有回答为什么此功能未标准化。这才是让我惊讶的原因。请考虑std::vector<A> arr(8, 7);new A[8](7);之间的效果问题

如果我们使用std::vector<A> arr(8, 7);,可以(不一定)按如下方式实施:

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!!!
}

如果C ++支持new A[8](7);它可以按如下方式实现:

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.
}

比较这两种方法,显然new A[8](7); 更快而不是std::vector<A> arr(8, 7);

此外,我也觉得new A[8](7);std::vector<A> arr(8, 7);

更简洁,更具表现力

无论如何,我认为C ++应该为程序员提供另一种替代工具,例如此功能。因为C ++哲学之一是“尽可能多地为你提供工具,但你不必为你不需要的东西买单。”

以下是原帖:

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
}

为什么在新建数组时不能指定构造函数?

为什么C ++标准不支持这样一个方便的功能? 理由是什么?

5 个答案:

答案 0 :(得分:3)

  

为什么C ++标准不支持这样一个方便的功能?理由是什么?

因为有更好的替代品可以替代(几乎)所有用例中的内置数组(是的,甚至是传递给C-API):std::vector用于动态数组(用new分配)和std::array用于堆栈分配的。

使用std::vector,你可以使用std::vector<A> arr(8, 7)(如WhozCraig评论的那样)创建一个包含8个元素的向量,用7初始化每个元素。省略第二个参数将使用它们的默认构造函数(内置使用0false)初始化类型。

除了这个和其他便利功能(特别是自动调整大小/ push_back())之外,std::vector优于使用new创建数组的最大优势是它遵守RAII,这意味着它一旦离开范围就会自动delete[]它的对象/内存 - 无论是“从函数的末尾掉下来”,return语句,break,{{ 1}},continue或抛出异常。

答案 1 :(得分:3)

Vector未实现如下:

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!!!
}

它的实现大致如下:

typedef UninitializedBackingStoreForA B;

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

即它使用未初始化的存储和新位置来构造元素。

所以你的直觉是错误的,矢量已经具有你所寻求的表现。每个元素调用一次构造函数,并且不需要默认构造函数。

答案 2 :(得分:2)

  

请考虑

之间的效果问题

你对实际的实施是错误的。在C ++ 11中,std::vector有一个Allocator对象,默认情况下为std::allocator。它首先通过调用Allocator::allocate来初始化内存,Allocator::construct返回原始内存;然后它调用{{1}}在原始内存上逐个构造对象,默认情况下使用placement new。换句话说,它与您指出的第二种可能的实现基本相同。

答案 3 :(得分:1)

对于pre-C ++ 11,你可以这样做:

new A[8]{ A(7), A(7), A(7), A(7), A(7), A(7), A(7), A(7) };

答案 4 :(得分:-1)

你试过for_each和lambda吗?

A* B = new A[8];

std::for_each(B, B+8, [](A &elem) {
    elem.n = 7;
});