为什么std :: vector的元素不需要默认构造函数?

问题描述:

我该如何编写我自己的数组类,以便不需要元素的默认构造函数?现在,当我执行new []来分配空间时,我需要一个默认构造函数。为什么std :: vector的元素不需要默认构造函数?

std :: vector没有。

他们如何做到这一点?

您可以分配一个字节块,然后使用placement new通过拷贝构造函数(当然不是默认构造函数)创建T(您的参数类型)的新实例,当新项目被推送到向量的背面时。这将不允许创建“一个N默认初始化的向量”(这是std :: vector可以做到的 - 这就是为什么它需要T有一个默认的构造函数来达到这个目的),但是你可以使向量开始空了,可以把Ts推到他们身上。

+0

我该如何分配空间呢? malloc的? – anon 2010-03-04 05:18:26

+2

@anon:看看'vector'是如何做的......它使用了一个分配器,例如'new_allocator'。在我的(旧的)Cygwin安装中,它的工作原理是这样的:'{return static_cast <_tp>(:: operator new(__ n * sizeof(_Tp))); }'或'malloc_allocator'这样做:'__ret = static_cast <_tp>(malloc(__n * sizeof(_Tp)));' – Dan 2010-03-04 05:34:24

std::vector不需要默认构造函数,因为它从不使用它。每次需要构建元素时,都会使用复制构造函数来执行此操作,因为每次需要复制时:现有向量元素或您自己提供的用于通过方法参数进行复制的元素(显式或隐式地,通过依靠默认参数

你可以写这样的一类以完全相同的方式:每次你需要你的数组构造新的元素时,需要用户进行复印提供的元素。在这种情况下,构建原始元素成为用户的责任。

它似乎来自你,如果std::vector“需要”一个默认的构造函数时,它都会只是意味着某个地方你依靠的一些vector小号方法默认参数,即它是谁试图默认 - 构建一个元素,而不是矢量。矢量本身再也不会尝试默认构建元素。

为了避免内存分配过程中的默认构造函数的要求,标准库分配原料未初始化的内存块,然后立即复制构造在原始内存块(这是一件好事new[]不能做的)新的元素。这个功能被封装在std::allocator类中。您也可以在代码中使用std::allocator,这意味着“魔术”也即时提供给您。

注:以上内容适用于C++ 11以前版本的C++语言规范。 C++ 11改变了很多东西。并且这些更改确实会创建内部使用默认构造函数的情况。

而且它可能是值得注意的是,即使是原来的C++ 98规范允许实现使用功能,以实现标准库接口超载代替默认参数。这意味着在形式上可能有一个有效的C++ 98实现std::vector,它使用默认构造函数内部

+3

另一方面,它们确实使用了一些非常相关的魔法:std ::分配器对象。 – 2012-04-21 00:44:30

+1

'std :: vector :: emplace_back()'确实会调用默认的构造函数。一般来说'emplace_back(Args ...)'调用带参数的构造函数'参数...' – 2015-08-13 14:00:14

+2

@Angelorf这个答案是在C++ 11发布前写的:)事实上C++ 11改变了'vector (5)' - 现在被指定为就地调用默认构造函数5次,而在C++ 03中则表示您默认构建一个“X”,然后向量使用复制构造5次,并且您的默认值在之后被销毁。 – 2015-12-21 09:30:34

std::vector只要求元素具有默认构造函数,如果以需要默认构造函数的方式使用它。所以这个代码(从已删除的答案被盗)将无法编译,因为X没有一个默认的构造函数:

#include <vector> 

struct X 
{ 
    X(int) {} 
}; 

int main(void) 
{ 
    std::vector<X> x(1); // vector of length 1, second argument defaults to X() !! 
    return 0; 
} 

但是,如果你写main喜欢这个:

int main(void) 
{ 
    std::vector<X> x; // make empty vector 
    x.push_back(X(1)); 
    return 0; 
} 

然后,它的工作原理精细。

+10

第一个版本不会编译,因为'std :: vector x(1)'是'std :: vector x(1,X())'的缩写。事实上,你*谁暗中使用默认构造函数,而不是'vector'。默认参数被评估为“在你身边”。 – AnT 2010-03-04 05:20:29

+0

@AndreyT:伟大的一点。 – Dan 2010-03-04 05:30:45