C++ 如何构造非默认可构造对象的std::vector?

C++ 如何构造非默认可构造对象的std::vector?,c++,c++11,C++,C++11,我在以下网站上遇到过这样的代码: #包括 #包括 #包括 #包括 int main() { 列表l={-4,-3,-2,-1,0,1,2,3,4}; 向量v(l.begin(),l.end()); 返回0; } 这是“示例”部分的一个片段。代码按预期编译和运行。但这怎么可能呢?std::reference_包装器不是默认可构造的。你怎样才能对这些东西做出std::vector?我总是把std::vector想象成一个动态数组。但是,如何从std::list初始化操作系统新提供给您的内存块呢 这

我在以下网站上遇到过这样的代码:

#包括
#包括
#包括
#包括
int main()
{
列表l={-4,-3,-2,-1,0,1,2,3,4};
向量v(l.begin(),l.end());
返回0;
}
这是“示例”部分的一个片段。代码按预期编译和运行。但这怎么可能呢?std::reference_包装器不是默认可构造的。你怎样才能对这些东西做出
std::vector
?我总是把
std::vector
想象成一个动态数组。但是,如何从
std::list
初始化操作系统新提供给您的内存块呢


这听起来可能是一个令人困惑的问题,但出于某种原因,我无法完全理解上面代码中发生的事情。那里发生了什么?

它之所以有效,是因为那里没有默认的初始化-列表中的元素用于复制和初始化向量

例如,以下方法不起作用:

std::vector<std::reference_wrapper<int>> v(42);
std::vectorv(42);

std::vector的构造函数首先获得一个大小合适的原始内存块(使用其
分配器)。然后构造对象。对于这里的特定构造函数

template<typename It>
std::vector::vector(It begin, It end);
模板
std::vector::vector(它开始,它结束);

它从迭代器的valuetype构造元素,因此每个
引用包装器
都是从
int
构造的(就地)。向量中的所有对象都是使用接受int的单参数构造函数构造的。这就是为什么在语义上不需要默认构造函数的原因


就实现而言,可以通过使用
malloc
而不是
new
分配内存来实现此行为(因此没有调用构造函数)然后在向向量添加元素时使用placement
new

我一直认为它是用空字节初始化的,如果有构造函数,则调用它。似乎无法向此类向量添加,但在构造时,它会为
l
中的每个元素调用非默认构造函数,像
std::reference(-4)
std::reference(-3)
,等等。@Robl:是的,你可以使用任何不需要默认构造函数的方法添加到它。@BenjaminLindley
emplace\u back
?@balki:是的,就是这样。或
放置
,或
插入
,或
推回
,或
调整大小
(2参数版本)。实际上,唯一需要默认构造函数的向量方法是单参数版本的resize,以及只接受一个int参数作为初始大小(或int和分配器)的构造函数。这就是这里的神奇之处。我一直认为std::vector在内部使用了new。这是有道理的。@MartinDrozdik它可以在内部使用
new
,但是
newunsignedchar[size*sizeof(T)]
而不是
newt[size]
。哦,我明白了。如果我编写了一个模板类,那么有些方法不适用于所有模板类型参数,可以吗?这被认为是良好的做法,还是仅仅是标准图书馆的特权?@MartinDrozdik:这是可能的,但有一些限制。只要方法没有实例化,那么它就可以了;然而,有时方法可以在您不要求的情况下实例化,例如
virtual
方法总是实例化的。
template<typename It>
std::vector::vector(It begin, It end);