vector::push_back and std::move
vector::push_back and std::move
我尝试了以下代码:
#include <iostream>
struct test{
test(){}
test(test const &){
std::cout<<__LINE__<<"n";
}
test(test&&){
std::cout<<__LINE__<<"n";
}
};
#include <vector>
#include <utility> // std::move
int main(){
auto&& tmp = test();
std::vector<test> v;
v.push_back(tmp);
std::cout<<__LINE__<<"n";
v.push_back(std::move(tmp));
return 0;
}
vs2013编译器输出:
6//份
18
9//移动
9//移动
g++和clang++输出:
6//份
18
9//移动
6//份
我的问题是:
是tmp测试的类型&;?tmp是右价吗?
如果tmp的类型是test&;,为什么第一个pushback没有使用move构造函数?
最后一个输出来自哪里?为什么vs2013和g++输出的结果不同?
谢谢。
第三个问题的答案:它来自andrew.punnett.评论的重新分配
tmp
的类型是test&&
吗?
是和否。tmp
是类型为test&&
的右值引用变量,但作为表达式的标识符tmp
具有类型test
和值类别左值。&
从来都不是表达式类型的一部分。
tmp
是右值吗?
否。标识符的任何使用都是一个左值表达式,甚至是右值引用的名称。Rvalue参考变量的访问基本上与lvalue参考变量相同;只有CCD_ 9能够区分。(通常您会使用decltype((tmp))
来避免说出差异。)
如果tmp的类型是test&;,为什么第一个pushback没有使用move构造函数?
因为右值引用的名称仍然是左值。若要获取右值表达式,请使用move(tmp)
。
最后一个输出来自哪里?为什么vs2013和g++输出的结果不同?
Clang和GCC默认情况下只为vector
中的一个对象腾出空间。添加第二个对象时,矢量存储被重新分配,导致对象被复制。他们为什么不动?因为move构造函数不是noexcept
,所以如果它抛出异常,就不可能撤消重新分配。
至于微软风投的两个举动,有两种可能性,你可以通过实验来区分——我手头没有副本。
- 默认情况下,MSVC在向量内为两个对象保留了足够的空间。第二步是来自内部局部变量
- MSVC忽略了移动构造函数为
noexcept
的要求,并调用它来执行重新定位。这将是一个错误,但在这种情况下,它掩盖了一个常见的错误
如果用deque
替换vector
,将看不到更多副本,因为deque
不允许具有可复制性。
Visual Studio还不支持noexcept关键字,并且可能不符合push_back的异常安全性。此外,额外的输出是增长时容量计算差异的结果。
#include <iostream>
#include <vector>
#include <utility> // std::move
struct Except{
Except(){}
Except(Except const &) {
std::cout<< "COPYn";
}
Except(Except&&) {
std::cout<< "MOVEn";
}
};
struct NoExcept{
NoExcept(){}
NoExcept(NoExcept const &) noexcept {
std::cout<< "COPYn";
}
NoExcept(NoExcept&&) noexcept {
std::cout<< "MOVEn";
}
};
template <typename T> void Test( char const *title,int reserve = 0) {
auto&& tmp = T();
std::cout<< title <<"n";
std::vector<T> v;
v.reserve(reserve);
std::cout<< "LVALUE REF ";
v.push_back(tmp);
std::cout<< "RVALUE REF ";
v.push_back(std::move(tmp));
std::cout<< "---nn";
}
int main(){
Test<Except>( "Except class without reserve" );
Test<Except>( "Except class with reserve", 10 );
Test<NoExcept>( "NoExcept class without reserve" );
Test<NoExcept>( "NoExcept class with reserve", 10 );
}
clang内的结果:
Except class without reserve
LVALUE REF COPY
RVALUE REF MOVE
COPY
---
Except class with reserve
LVALUE REF COPY
RVALUE REF MOVE
---
NoExcept class without reserve
LVALUE REF COPY
RVALUE REF MOVE
MOVE
---
NoExcept class with reserve
LVALUE REF COPY
RVALUE REF MOVE
---
- Usages of std::move
- 在C++中对T*类型执行std::move的意外行为
- 关于std::move的使用,是否有编译警告
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 通过实例理解std::move及其目的
- 返回一个带有 std::move 的对象并链接函数
- 当 std::move 与 C 样式数组或不移动对象时会发生什么
- std::move a const std::vector in a lambda capture
- "std::forward"和"std::move"真的不生成代码吗?
- 如何在没有 std::move 的情况下移动临时对象
- 关于在成员重载中使用 std::move() 的问题
- 显式清除 std::move 之后的源资源
- std::move 如何使原始变量的值无效?
- 复制elision、std::move和链式函数调用
- 如果真的需要std::move,我们应该什么时候声明右值refs
- 使用std::move将std::unique_ptr作为qt信号参数传递
- 无法使用带有 std::move 的自定义删除器插入 std::unique_ptr
- C++:我应该在 return 语句中显式使用 std::move() 来强制移动吗?
- 编译器是否足够聪明,以至于 std::move 变量超出范围?
- std::move() 或其在局部变量上的显式等价物可以允许 elision 吗?