[英]Re-using code for lvalues and rvalues
假设我有一个复制构造函数。 该构造函数调用函数的层次结构,将复制的对象作为左值引用传递。
现在,我还有一个移动构造函数,它基本上可以使用与复制构造函数相同的函数层次结构。 这将起作用,因为我可以将rvalue参数传递给左值层次结构。
但是在层次结构中的某个位置,我有一个函数,它将在左值情况下复制资源并在右值情况下“窃取”资源。
有没有办法确定传递给该函数的左值引用是否源自右值? 我猜不会。 或者,当您具有用于复制的功能层次结构时,可以将其用于复制和移动构造,而这些功能仅在很少的功能上有所不同,什么是通用方法?
代码示例:
class A{
A(const A& a){
initFrom(a);
}
A(A&& a){
initFrom(a);
}
void initFrom(const A& a){
// call a hierarchy of functions, of which one of them calls initResource(const A&)
}
void initResource(const A& a){
if(a == rvalue reference){ // **** Here's the question... ****
// steal resource
this->ptr = a.ptr;
a.ptr = nullptr;
}
else{
// copy resource
this->ptr = allocate...
copy from a.ptr to this->ptr
}
}
这是完美转发的典型示例:
template <typename T>
A(T && t) { initFrom(std::forward<T>(a)); }
template <typename T>
void initFrom(T && t)
{
// other calls
initResource(std::forward<T>(t));
}
void initResource(A const & rhs) { /* copy from rhs */ }
void initResource(A && rhs) { /* move from rhs */ }
(似乎您应该能够将initFrom
合并到构造函数中,否则您的类可能试图做太多事情,因此应将其重构为单一职责组件。)
这里的一种替代方法是修改initFrom
以接受“通用引用”以允许引用折叠,然后使用std::forward
进行完美转发。 然后,您可能需要重新分解其余的呼叫层次结构。
class A{
A(const A& a){
initFrom(a);
}
A(A&& a){
initFrom(a);
}
template <typename B>
void initFrom(B&& a){ // reference collapsing applies
// call a hierarchy of functions, of which one of them calls initResource(const A&)
initResource(std::forward<B>(a));
}
void initResource(A&& a){
// steal resource
this->ptr = a.ptr;
a.ptr = nullptr;
}
void initResource(const A& a){
// copy resource
this->ptr = allocate...
//copy from a.ptr to this->ptr
}
};
我认为一个更简单的选择是在调用initFrom
之前initFrom
资源“移动”到您的类中。
A(A&& a){
this->ptr = a.ptr;
a.ptr = nullptr;
initFrom(a);
}
但是您的里程可能会有所不同。
根据您的调用层次结构以及所有这些功能必须做什么(除了传递对象之外),如果您打算将对象存储在类中,则可以使用另一种技术。
class A {
A(const A& a) {
initFrom(A(a)); // take a copy here
}
A(A&& a) {
initFrom(std::move(a)); // move here
}
void initFrom(A&& a) {
initResource(std::move(a)); // just pass down
}
void initResource(A&& a) {
// you already have your copy of a here that you can store completely
// or take its guts
}
这样,您只需要将所有方法实现一次(用于右值引用),并且是否直接在方法调用中处理移动或复制副本。 注意,始终必须传递std :: move()来传递右值引用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.