简体   繁体   中英

C++ rvalue forwarding

According to Resharper , this here is invalid c++:

class IData{
    IData();
    virtual doStuff() = 0;
}
class MyData: public IData{
    MyData(MyData&& mdrv);
    doStuff() override{/*....*/};
}
class DataUser(){
    DataUser(IData& d){   //all explicits are ommitted for brevity, don't call me out on that please :)
        d.doStuff();
    }
}
int main(){
    DataUser d(MyData()); //it complains here: Binding Rvalue Reference to lvalue Reference is a non standard MSVC extension
}

I cant make IData& const , because doStuff does stuff (duh!)

What I did was this:

 class DataUser(){
     DataUser(IData& d){
         d.doStuff();
     }
     DataUser(IData&& d): DataUser(d){  //added this, no complains anywhere
     }
 }

Now my Questions are:

  1. Is the first one really non standard complying c++?
  2. How does the addition of my cheaty constructor change anything, and is it standards complying?
  3. If neither of these are valid (which is what i fear), how could i create cheaty constructor 2.0, letting me pass a non const rvalue? [without templated perferct forwarding please, i want to retain my source entirely in .cpp] All IDatas have valid move constructors and assignment operators

I was able to figure this out due to the amazing help by @Incomputable.

It boils down to the facts that:

  • Rvalue references extend the lifetime of the object that they are holding until they go out of scope
  • Const Lvalue References do the same, but obviously cant be modified
  • Non const Lvalue References that are initialized with rvalue ref do NOT extend the lifetime of the rvalue
  • Due to reference collapsing , the delegate constructor calls the lvalue constructor, and not itself

Additional resources (provided again by @Incomputable) can be found

Here and Here (especially the paragraph entitled Rvalue references is very good)

That is why

class DataUser(){
    DataUser(IData& d){ 
        d.doStuff();
    }
}
int main(){
    DataUser d(MyData()); //lvalue ref is initalized  with rvalue, Rvalue goes out of scope --> UB
}

but

class DataUser(){
        DataUser(IData& d){ 
            d.doStuff();
        }
        DataUser(IData&& d): DataUser(d){ //the rvalues lifetime is extended until the constructor exits and d goes out of scope
        }
    }
    int main(){
        DataUser d(MyData()); //this works like a charm and is perfectly legal
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM