Kon*_*lph 28 c++ stdvector move-semantics c++11
可能重复:
如何在向量增长时强制执行移动语义?
insert,push_back和emplace(_back)可能导致的重新分配std::vector.我很困惑地看到以下代码复制元素而不是在重新分配容器时移动它们.
#include <iostream>
#include <vector>
struct foo {
int value;
explicit foo(int value) : value(value) {
std::cout << "foo(" << value << ")\n";
}
foo(foo const& other) noexcept : value(other.value) {
std::cout << "foo(foo(" << value << "))\n";
}
foo(foo&& other) noexcept : value(std::move(other.value)) {
other.value = -1;
std::cout << "foo(move(foo(" << value << "))\n";
}
~foo() {
if (value != -1)
std::cout << "~foo(" << value << ")\n";
}
};
int main() {
std::vector<foo> foos;
foos.emplace_back(1);
foos.emplace_back(2);
}
Run Code Online (Sandbox Code Playgroud)
在我使用我的特定编译器(GCC 4.7)的特定机器上,这将打印以下内容:
foo(1)
foo(2)
foo(foo(1))
~foo(1)
~foo(1)
~foo(2)
Run Code Online (Sandbox Code Playgroud)
但是,删除复制构造函数(foo(foo const&) = delete;)时,会生成以下(预期)输出:
foo(1)
foo(2)
foo(move(foo(1))
~foo(1)
~foo(2)
Run Code Online (Sandbox Code Playgroud)
这是为什么?移动通常不会比复制更有效率,或者至少效率不高吗?
值得注意的是GCC 4.5.1做了预期的事情 - 这是GCC 4.7中的回归还是一些狡猾的聪明优化,因为编译器看到我的对象复制便宜(但是如何?!)?
另请注意,我确保这是由重新分配引起的,通过实验foos.reserve(2);性地在插入前放置; 这导致既不复制也不移动.
Jer*_*fin 12
简短的回答是我认为@BenVoigt基本上是正确的.
在reserve(§23.3.6.3/ 2)的描述中,它说:
如果除非由非CopyInsertable类型的move构造函数抛出异常,则不会产生任何影响.
[并且resize§23.3.6.3/ 12中的描述要求相同.]
这意味着如果T是CopyInsertable,则会获得强大的异常安全性.为了确保它,它只能使用移动构造,如果它(通过未指定的方式)推断移动构造将永远不会抛出.但是,无法保证其中任何一个throw()或noexcept将是必要的或足够的.如果T是CopyInsertable,它可以简单地选择始终使用复制构造.基本上,正在发生的是标准需要复制构造式语义; 编译器只能在as-if规则下使用move构造,并且可以自由定义何时或是否运用该选项.
如果T不是CopyInsertable,重新分配将使用移动构造,但异常安全取决于T的移动构造函数是否可以抛出.如果它没有抛出,你会获得强大的异常安全性,但是如果它抛出,你就不会(我认为你可能得到了基本的保证,但也许甚至没有,绝对没有).
Tip-of-trunk clang + libc ++获取:
foo(1)
foo(2)
foo(move(foo(1))
~foo(2)
~foo(1)
Run Code Online (Sandbox Code Playgroud)
如果noexcept从移动构造函数中删除,则获得复制解决方案:
foo(1)
foo(2)
foo(foo(1))
~foo(1)
~foo(2)
~foo(1)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6493 次 |
| 最近记录: |