从new_S
那里返回后没有“RValue 向量”(我假设您的意思是构造函数的右值引用参数)。右值引用仅在 S 的构造期间存在。
对您的代码说几句话:std::forward
在这里磨损。仅在完美转发非通用引用时才需要它,并且std::vector<T>
uns 不是通用引用而是右值引用(请参见此处)。std::move
在这种情况下使用。
话虽如此,您不应在构造函数中通过 rvalue-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 放置在向量内。
- 在您的写作中,构造函数的右值 ref 参数绑定到临时。在我的写作中,
s
使用临时调用向量的移动构造函数进行初始化。在那之后,临时是空的,并s
拥有带有 T 的内存块。
- 在 的初始化中
s_
,参数被移动。这意味着,从临时(在您的写作中)或从(在我的写作中)s_
构建移动。s
之后,临时/s
为空并s_
拥有在步骤 1 中分配的内存块。
s_
构造正确,它是一个有效的对象。一个对象X
只有在移动它时才会“无效”,即当你调用move(X)
. Y
您通过将另一个对象移动到它来构造的对象(X
意思是:通过 移动构造它auto Y = move(X);
)永远不会是无效的。在构造时使对象无效将是非常糟糕和无用的,C++ 将是一种损坏的语言。