具有移动操作和重新值转发的对象生存期
Objects lifetime with move operation and rvalue forwarding
我想知道以下代码是否有效
特别是,在调用new_S之后,我对这里涉及的对象的生存期感到困惑
根据我的理解,在处理初始值设定项列表时,T将被复制,并且可能在向量移动构造函数中被复制
那么RValue向量呢?从new_S返回后仍然有效吗?我会说不,但我绝对不确定
struct T
{
int t;
};
struct S
{
S(std::vector<T>&& s) : s_(std::forward<std::vector<T>>(s)) {}
std::vector<T> s_;
};
S* new_S()
{
return new S{{{1}, {2}, {3}}};
}
从new_S
返回后,没有"RValue vector"(我假设你指的是构造函数的右值引用参数(。右值参考仅存在于S.的构建过程中
对你的代码说几句话:std::forward
在这里工作。它只需要完美地转发非全局引用,而std::vector<T>
不是通用引用,而是右值引用(请参阅此处(。在这种情况下使用std::move
。
话虽如此,您不应该在构造函数中传递右值ref。相反,按值传递:
struct S
{
S(std::vector<T> s) : s_{std::move(s)} {}
std::vector<T> s_;
};
这样,您就可以获得任何传递值的最佳解决方案,请参阅此处:
- 如果传递了一个右值,则
s
由参数移动构造,然后s_
由s
移动构造。没有复制 - 如果传递了一个左值,则
s
被复制构造,然后s_
被从s
移动构造。只制作了一份必要的副本
最后但同样重要的是:不要使用原始指针和new
/delete
。相反,使用智能指针:
unique_ptr<S> new_S()
{
return std::make_unique<S>({{1}, {2}, {3}});
}
make_unique
附带了C++14,如果您的库还没有,您可以轻松地推出自己的。
更新:要回答您关于对象生存期的问题:在new_S
中,您基本上有4或5个对象:
- 构造的S及其内部的向量
- 传递给构造函数的初始值设定项列表
- 根据初始值设定项列表构造的临时向量
- 在我编写函数时,参数
s
是它自己的对象
现在发生了什么:
- 初始值设定项列表用于创建临时向量对象,它是传递给构造函数的右值。在构造临时的过程中,分配一块内存来将三个T放置在向量内
- 在编写过程中,构造函数的rvalue-ref参数绑定到临时的。在我的写作中,
s
是用临时的、调用向量的move构造函数初始化的。之后,临时内存为空,s
拥有具有T的内存块 - 在初始化
s_
时,会移动参数。也就是说,s_
是从临时(在你的写作中(或s
(在我的写作中中(构造的。之后,临时/s
为空,并且s_
拥有在步骤1中分配的存储器块
s_
构造正确,是一个有效的对象。对象X
仅在移动时(即,当您调用move(X)
时(变为"无效"。通过将另一个对象X
移动到它来构造的对象Y
(意思是:通过auto Y = move(X);
移动构造它(永远不会无效。在构造中使对象无效将是非常糟糕和无用的,C++将是一种破碎的语言。
相关文章:
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- CMake-按正确顺序将项目与C运行时对象文件链接
- 空基优化子对象的地址
- 将对象数组的引用传递给函数
- 你能重载对象变量名本身返回的内容吗
- C++使用整数的压缩数组初始化对象
- 完美的对象转发阵列
- 自定义类型转换运算符在转发引用上调用时不起作用(当对象按值传递时有效)
- 将可变参数函数参数转发到 std::function 对象
- 如何构造一个 std::variant 类型对象,其自身 Templated 和构造函数转发参数
- 如何从常量引用或通过转发模板临时构造对象
- 转发通用可可对象的返回值
- 可调用对象的完美转发
- 使用std ::函数或转发引用作为高阶函数的通用对象输入参数
- 将构造函数转发到成员对象
- 哪种设计更好:提供对所属对象的直接访问,或者为所属对象提供所属对象转发方法
- 完美转发对象的成员
- 具有移动操作和重新值转发的对象生存期
- C++模板类类型作为参数转发到对象的模板函数