I want to define a wrapper class (BoxB) that takes another class (BoxA) as an argument by reference and stores the reference. This is not too complicated as long as the argument is an lvalue. However I would like a constructor to accept also a prvalue, esp. a temporary value, whose lifetime would somehow be extended to match that of the container. It would look like this. Is it possible?
1 2 3 4 5 6
|
class boxB{
public:
BoxA & myBox;
boxB(BoxA & b):myBox(b){}
boxB(BoxA && b):myBox( ... ){} // .... would magically make b live as long as the object
};
| |
It’ve tried passing the prvalue as a const refer
boxB(BoxA & a)
but the lifetime of the object ends at the end of the statement (as I can see when tracing calls to the destructor of boxA).
I thought then that the solution could be to write an alternate constructor taking a prvalue reference as an argument
boxB(BoxA && b)
and to move the object during initialization. This is what the code hereunder is attempting, but I can see it is not working because the container (boxB) is initialized with a fresh copy of the argument, not a moved copy.
But even if it is possible to move the temporary object into a permanent member value, there would still be an issue because the destructor of that temporary would still be called at the end of the statement, which would make a mess.
Also, in the code, I attempt to move the prvalue into a non-reference member variable. Ideally, it should be into a new object, and the member variable should be a reference or a pointer, which would be deleted at destruction.
Finally, what ultimatly want is a templated wrapper class and the prvalue argument would be supplied first to a factory function.
Please note that BoxA and BoxB inherits from a class Box, just because I want to implement an instance counter without overloading the default constructor of BoxA (I assume there is a default move constructor)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
#include <iostream>
int count = 0;
class box{ //box is just there to implement the counter facility without changing the default constructors of BoxA
public:
int num;
box():num(++count){std::cout << "created "<<num << std::endl;}
~box(){std::cout << num<<" is dead" << std::endl;}
};
class boxA:public box{
public:
};
class boxB:public box{
public:
boxA & myA;
boxA altA; ///ideally this should be a reference or a pointer.
boxB(boxA & Aref):myA(Aref){std::cout <<"&->"<<myA.num << std::endl;}
boxB(boxA && Aref):altA(std::move(Aref)),myA(altA){myA.num+=100;std::cout <<"&&->"<<myA.num << std::endl;}
};
int main()
{
boxB y(boxA{});
std::cout << "****"<<y.myA.num<<"****" << std::endl;
return 0;
}
| |
created 1
created 2
&&->101
1 is dead
****101****
101 is dead
2 is dead
|
The line
shows that the temporary is destructed and still contains the original counter value, so what was changed to 101 is a fresh copy not a move