It is possible to mark a member function to be called when it is applied to a temporary object (or object of right-type type), for that reason &&
is added at the end of the signature of the function, this is known as " reference qualifiers " or " reference to right-value for *this
", if you use these functions at your Objeto
:
std::vector<int> const& Coleccion() &
{
if( coleccion.empty() )
RellenarColeccion();
return coleccion;
}
// Esta version de Coleccion sera llamada cuando el objeto sea un temporal
std::vector<int> Coleccion() &&
{
if( coleccion.empty() )
RellenarColeccion();
return std::move(coleccion);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <-- movemos la coleccion fuera del temporal
}
In the version that uses a reference to the right value for *this
, we use std::move
to transform the coleccion
of the temporary object into a vector value-right, which will be used to construct the resulting std::vector<int>
that, when receiving a right-value, it will move the content instead of copying it 1 . To see if this works as you need, I made some changes in your example class:
class Objeto
{
using type_t = chivato;
::vector<type_t> coleccion;
Objeto() { std::cout << this << ' ' << __FUNCTION__ << '\n'; }
friend Objeto NuevoObjeto(); // Otorgamos acceso a los miembros privados para la factoria
void RellenarColeccion()
{ coleccion.emplace_back(); } // Anyadimos un objeto como prueba
public:
~Objeto() { std::cout << this << ' ' << __FUNCTION__ << '\n'; } // mostramos mensaje al destruir
Objeto(Objeto const&) = delete;
Objeto(Objeto &&) = default;
std::vector<type_t> const& Coleccion() &
{
std::cout << "No temporal\n";
if( coleccion.empty() )
RellenarColeccion();
return coleccion;
}
std::vector<type_t> Coleccion() &&
{
std::cout << "Temporal\n";
if( coleccion.empty() )
RellenarColeccion();
return std::move(coleccion);
}
};
I added some messages in the construction and destruction of Objeto
and changed the type of the object contained in the collection to this:
struct chivato
{
chivato() { std::cout << this << ' ' << __FUNCTION__ << '\n'; }
~chivato() { std::cout << this << ' ' << __FUNCTION__ << '\n'; }
};
With these changes, if we execute this code in main
:
std::cout << "Objeto en main\n";
Objeto o1 = NuevoObjeto();
std::cout << "Referencia a coleccion\n";
auto& v1 = o1.Coleccion();
std::cout << "\nObjeto temporal del que se obtiene coleccion\n";
auto v2 = NuevoObjeto().Coleccion();
std::cout << "Despues\n";
We have this exit 2 :
Objeto en main
0x000000000001 Objeto
Referencia a coleccion
No temporal
0x0000001 chivato
Objeto temporal del que se obtiene coleccion
0x000000000002 Objeto
Temporal
0x0000002 chivato
0x000000000002 ~Objeto
Despues
0x0000002 ~chivato
0x000000000001 ~Objeto
0x0000001 ~chivato
We see that the first Objeto
( 0x000000000001
) creates a collection with the element 0x0000001
and that collection is read through the function Coleccion
that does not apply over temporary, we do not see that the element 0x0000001
be destroyed.
In the second part a temporary Objeto
( 0x000000000002
) is created that contains the 0x0000002
element and then the Objeto
is destroyed without the element ( 0x0000002
) being destroyed, that means that the collection has been moved, we can also see that it has been called the version of Coleccion
that is called over temporary.
After the message Después
are called the destructors of the collection element of Objeto
created temporarily from the factory ( 0x0000002
), then the destructor of the first Objeto
( 0x000000000001
) created is called the which calls the destructor of its unique element ( 0x0000001
).
This behavior shows us that there has been no copy of the collection obtained from the storm (if there had been a copy it would be an additional construction-destruction of collection elements).
You can see the code working In Wandbox 三 へ (へ ਊ) へ ハ ッ ハ ッ .
1 Attention, using std::move
in a% instruction return
avoids optimizing the return value .
2 I have edited the memory addresses, for clarity and because different executions are different values.