C++ 为什么要将T型放置在需要可移动构造的向量末端?
为什么公共构造函数(和析构函数)不足以将C++ 为什么要将T型放置在需要可移动构造的向量末端?,c++,c++11,move,stdvector,move-semantics,C++,C++11,Move,Stdvector,Move Semantics,为什么公共构造函数(和析构函数)不足以将t类型的对象放置在向量的后面?以下代码段格式不正确 #include <vector> struct Foo { Foo() {} Foo(int) {} ~Foo() {} Foo(const Foo&) = delete; Foo& operator=(const Foo&) = delete; }; int main() { std::vector<Foo> vfoo(10
t
类型的对象放置在向量的后面?以下代码段格式不正确
#include <vector>
struct Foo {
Foo() {}
Foo(int) {}
~Foo() {}
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
};
int main() {
std::vector<Foo> vfoo(10);
vfoo.emplace_back();
}
#包括
结构Foo{
Foo(){}
Foo(int){}
~Foo(){}
Foo(const Foo&)=删除;
Foo&运算符=(const Foo&)=删除;
};
int main(){
std::向量vfoo(10);
vfoo.emplace_back();
}
emplace\u back
要求Foo
至少是可移动构造的,并且此代码无法编译,因为移动构造函数与复制构造函数一起被删除。但是我想象emplace\u back
使用placement new调用默认构造函数。在您的示例中,向量是用10
元素构造的
然后添加一个。如果capacity()
中没有更多的空间,则必须分配一个新的缓冲区,必须将已有的10个元素移到其中,然后添加新元素
您会注意到上面的单词move
——这就是您需要move的原因
此外,即使您没有元素,或者您仔细确保有足够的容量,编译器也无法知道:移动现有元素的代码将被编译(如果不运行),您将得到错误
vector
中缺少“向后推,我保证已经有容量”方法。再加上“设置容量,放弃任何现有元素”,可以让您添加元素而不需要移动或复制ctor回退。在emplace
发明之前,所有添加元素都需要一个副本或移动:在C++11之前,所有添加元素都需要一个副本。这两种方法缺乏奇怪的语义,只是为了允许不可移动类型限制使用向量
,这并不奇怪
我鼓励您编写一个包含这两个扩展(或类似的扩展)的容器,并建议将其添加到C++中:这可能对高性能用例也有帮助(编译器能够证明我确实确保了在我的经验中足够的容量).当调整容器大小并且需要复制现有内容时,您预计会发生什么?请参阅@o11c
emplace
和emplace\u back
上“参数”下的“类型要求”是不同的事情,无论如何,问题是为什么会有这样的要求,不是需求是什么,因为它是这样定义的。“这么简单!”大卫汉姆说。对问题是这样做的理由。如果对象不可移动,但需要重新分配,是否可以删除可移动的要求,并使emplace\u back
抛出?(如果我们不想更改新的emplace函数,也可以使用另一个名称的新emplace函数)@mattmcnab肯定需要单独的函数。就我所知,不可能准确地检测到某个东西是否是可插入的。@T.C.但你可以准确地检测到它(但移动实际上移动的事实无法确定,但这似乎不合理),或者还有其他原因吗?(我猜分配器会很晚失败?@Yakk如何在普通代码中检测到它(没有内部代码)?当然,您可以检测到在直接上下文中,分配器_traits::construct(m,p,rv)
是否格式良好,但这并不意味着什么,因为实际上要中断的是调用内部的移动。然后,有些东西的移动将在重载解析中失败(move-ctor-deleted或nonexistent),有些东西的移动构造函数将假装存在,然后无法实例化,您只能检测到前者。