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

ano*_*non 25 c++ vector default-constructor

如何编写自己的数组类,不需要为其元素提供默认构造函数?现在,当我执行new []来分配空间时,我需要一个默认的构造函数.

std :: vector没有.

他们如何做到这一点?

AnT*_*AnT 30

std::vector不需要默认构造函数,因为它从不使用它.每次需要构造一个元素时,它都是通过使用复制构造函数来完成的,因为每次都有复制的东西:现有的vector元素或你自己提供的元素,用于通过方法的参数进行复制(显式或隐式,依赖在默认参数上)

您可以以完全相同的方式编写类似的类:每次需要在数组中构造新元素时,都需要用户提供复制元素.在这种情况下,构建该原始元素将成为用户的责任.

每当它看起来好像std::vector"需要"你的默认构造函数时,它只是意味着你依赖某些vectors方法的默认参数,即试图默认构造一个元素,而不是向量.另外,向量本身永远不会尝试默认构造元素.

为了避免在内存分配期间的默认构造函数要求,标准库分配原始未初始化的内存块,然后立即复制构造该原始内存块中的新元素(这是不可行的new[]).此功能在std::allocator课堂上封装.您也可以std::allocator在代码中使用,这意味着您也可以立即使用"魔法".

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

此外,值得注意的是,即使是最初的C++ 98规范也允许实现使用函数重载而不是默认参数来实现标准库接口.这意味着正式地可以在内部std::vector使用默认构造函数的有效C++ 98实现.

  • @Angelorf这个答案是在C++ 11发布之前编写的:)实际上C++ 11改变了`vector <X> x(5)`的行为 - 现在被指定为就地调用默认构造函数5次,而在C++ 03中,它意味着你默认构造一个`X`,然后矢量使用复制构造5次,你的默认值在之后销毁. (4认同)
  • 另一方面,他们确实使用了一些非常相关的魔法:std :: allocator对象. (3认同)

Dan*_*Dan 11

std::vector如果您以需要默认构造函数的方式使用它,则只需要元素具有默认构造函数.所以这段代码(从删除的答案中窃取)将无法编译,因为X没有默认的ctor:

#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;
}
Run Code Online (Sandbox Code Playgroud)

但如果你这样写main:

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

然后它工作正常.

  • 第一个版本不会编译,因为`std :: vector <X> x(1)`是`std :: vector <X> x(1,X())`的简写.实际上*你*谁暗示使用默认构造函数,而不是`vector`.默认参数"在您身边"进行评估. (10认同)

Ale*_*lli 7

您可以分配一个字节块,然后在将新项目推送到向量的后面时,使用放置newT通过复制构造函数(当然不是默认构造函数)创建(您的参数类型)的新实例.这将不允许进行"N默认初始化TS的载体"(其中的std ::向量可以-这就是为什么它确实需要吨至具有用于此目的的默认构造函数),但你能有这样的开始向量空的,可以把Ts推到他们身上.

  • @anon:看看`vector`是如何做到的......它使用了一个分配器,例如`new_allocator`.在我的(旧)Cygwin安装中它的工作方式如下:`{return static_cast <_Tp*>(:: operator new(__ n*sizeof(_Tp))); 或者``malloc_allocator`这样做:`pointer __ret = static_cast <_Tp*>(malloc(__ n*sizeof(_Tp)));` (2认同)