:什么是返回前向(通用)引用的最自然的方式?
struct B{
template<class Ar> friend
/* 1*/ Ar&& operator<<(Ar&& ar, A const& a){...; return std::forward<Archive>(ar);}
template<class Ar> friend
/*OR 2*/ Ar& operator<<(Ar&& ar, A const& a){...; return ar;}
template<class Ar> friend
/*OR 3*/ Ar operator<<(Ar&& ar, A const& a){...; return std::forward<Ar>(ar);}
template<class Ar> friend
/*OR 4*/ Ar operator<<(Ar&& ar, A const& a){...; return ar;}
/*OR 5*/ other??
}
我想到的情况是一个类似流的对象,它被构造并立即使用。例如:
dosomethign( myarchive_type{} << B{} << B{} << other_unrelated_type{} );
发布于 2018-09-14 14:08:21
返回rvalue引用很少是个好主意。罕见的例外情况是,您正在编写逻辑上等效于std::forward
的函数。
它之所以是个坏主意,是因为引用生存期扩展不是传递性的,而且您很容易不小心得到挂起的引用。
const auto& foo = some_operation;
如果some_operation
是prvalue表达式,则临时的生存期将扩展到foo
的生存期。但是,如果some_operation
是:
foo( some_prvalue_expression )
当foo
接受一个rvalue引用并返回它时,您将得到一个悬空引用。
对于移动成本低的类型,解决方案很简单:
struct B{
template<class Ar> friend
Ar operator<<(Ar&& ar, A const& a){...; return std::forward<Archive>(ar);}
}
如果传递一个lvalue,则通过引用返回,如果传递一个rvalue,则返回值。
现在,引用生存期扩展正常工作。
这要求你的类型是便宜的移动;所以
myarchive_type{} << B{} << B{} << other_unrelated_type{};
结果myarchive_type{}
被移动3次。
如果您的类型移动起来不便宜,可以考虑简单地阻止rvalue版本;缺乏安全性使其不值得。
对于一个具体的例子,请看一下这个函数:
template<class C>
struct backwards {
C c;
auto begin() const {
using std::rbegin;
return rbegin(c);
}
auto end() const {
using std::rend;
return rend(c);
}
};
template<class C>
backwards(C&&) -> backwards<C>;
(如果我把扣减指南搞错了,很抱歉)。
现在我们这样做:
for( auto x : backwards{ std::vector<int>{1,2,3} } ) {
std::cout << x << ",";
}
vector
被移动到backwards
中,但是如果我们这样做:
auto vec = std::vector<int>{1,2,3};
for( auto x : backwards{ vec } ) {
std::cout << x << ",";
}
不复制。
如果没有“创建副本并在传递rvalue的情况下返回它”,上面的第一个for循环将有一个悬空引用。
我看到了一些建议或建议的想法,它们试图概括引用生存期扩展,或者至少向编译器提供提示,说明函数的返回值取决于传递给它的参数的生存期,以便在以这种方式使用悬空引用时,它可以生成错误/警告。据我所知,没有一家公司把它变成了C++标准。
在不这样做之前,随意返回一个参考价值对我的血液来说太危险了。
假设你考虑搬家很贵。好吧,这是可行的:
std::invoke([&](auto&& ar){
dosomething( ar << << B{} << B{} << other_unrelated_type{} );
}, myarchive_type{} );
它接受临时的myarchive_type{}
并将其存储在一个rvalue引用中。
然后它把它传递给一只羔羊。在lambda内部,名称ar
是一个lvalue。我们继续在兰博达内安全使用它。
https://stackoverflow.com/questions/52325198
复制相似问题