编译器在将 std::unique_ptr 推回 std::vector 时不会失败
Compiler doesn't fail when pushing back a std::unique_ptr into a std::vector
除非使用std::move
,否则unique_ptr
不能推回std::vector
,因为它是不可复制的。但是,让我们F
是一个返回unique_ptr
的函数,则允许操作std::vector::push_back(F())
。下面是一个示例:
#include <iostream>
#include <vector>
#include <memory>
class A {
public:
int f() { return _f + 10; }
private:
int _f = 20;
};
std::unique_ptr<A> create() { return std::unique_ptr<A>(new A); }
int main() {
std::unique_ptr<A> p1(new A());
std::vector< std::unique_ptr<A> > v;
v.push_back(p1); // (1) This fails, should use std::move
v.push_back(create()); // (2) This doesn't fail, should use std::move?
return 0;
}
(2)
是允许的,但(1)
不是。这是因为返回值以某种方式隐式移动吗?
在(2)
,真的有必要使用std::move
吗?
std::move(X)
本质上的意思是"在这里,将X视为临时对象"。
create()
首先返回一个临时std::unique_ptr<A>
,因此不需要move
。
如果您想了解更多信息,请查看值类别。编译器使用值类别来确定表达式是否引用临时对象("右值")或不引用("左值")。
p1
是左值,create()
是右值。
std::vector::push_back()
有一个重载,它将右值引用作为输入:
void push_back( T&& value );
create()
的返回值是一个未命名的临时值,即右值,因此可以按原样传递给push_back()
,而无需对其使用std::move()
。
仅当传递命名变量(即左值)时才需要std::move()
,其中需要右值。
在 C++11 中,我们得到了移动构造函数和右值语义。
std::move(X) 只是一个转换到 rvalue 的转换,它将 X 转换为 X&仅此而已。比移动 ctor 接管工作,移动构造函数通常会"窃取"参数持有的资源。unique_ptr有一个移动控制者。
函数返回值已经是一个右值(除非函数返回注释中@HolyBlackCat指示的左值引用),这将触发移动 ctor 而无需任何额外的强制转换。由于移动 ctor 是为unique_ptr定义的,因此它将编译。
也是v.push_back(p1)的原因;失败是:您尝试使用左值调用复制构造函数,但它失败unique_ptr因为它没有复制 CTOR。
还值得知道的是,由于编译器能够移动未显式移动的对象(NRVO),因此它也将起作用。
#include <iostream>
#include <vector>
#include <memory>
class A {
public:
int f() { return _f + 10; }
private:
int _f = 20;
};
std::unique_ptr<A> create() {
std::unique_ptr<A> x (new A);
return x;
}
int main() {
std::unique_ptr<A> p1(new A());
std::vector< std::unique_ptr<A> > v;
//v.push_back(p1); // (1) This fails, should use std::move
v.push_back(create()); // (2) This doesn't fail, should use std::move?
return 0;
}
- 使用std::vector的OpenCL矩阵乘法
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- std::vector的包装器,使数组的结构看起来像结构的数组
- 编译器如何区分std::vector的构造函数
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 在std::vector上存储带有模板的类实例
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 为什么std::vector比数组慢
- std::vector::迭代器是否可以合法地作为指针
- 如何将二进制格式的 C++ 对象的 std::vector 保存到磁盘?
- 为什么std::vector和std::valarray初始化构造函数不同
- ";结果类型必须是可从输入范围的值类型""构造的;创建std::vector时
- 在没有未定义行为的情况下实现类似std::vector的容器
- 如何调整 std::vector of Eigen::MatrixXd 的大小
- 使用 std::vector::reverse_iterator 将 int 序列化为字节向量?
- 如何将AERT_Allocate与 std:vector 一起使用
- 推导 std::vector::back() 的返回类型
- 如何将原始字节附加到 std::vector?
- std::vector 没有重载函数的实例与参数列表匹配
- 如果 KEY 是 std::list 或 std::vector 而不是值,那么 std::map 的默认行为是什么?