I have a situation which I cannot wrap my head around. I define a non-copy-able struct and want to in-place construct it in a tuple. If I do so, it is copied. I thought the problem may be std::make_tuple
, but it isn't.
If instead I construct the object, then move it in the tuple, things work as expected.
Demonstration (I use std::exit
to prevent the output of normal destruction).
#include <tuple>
#include <iostream>
#include <cstdlib>
struct MoveMe {
MoveMe(size_t s) : size(s) {}
MoveMe(MoveMe&&) = default;
MoveMe(const MoveMe&) = delete;
MoveMe& operator=(MoveMe&&) = default;
MoveMe& operator=(const MoveMe&) = delete;
~MoveMe() {
std::cout << "Destroyed" << std::endl;
}
size_t size = 0;
};
int main(int, char**) {
std::cout << "Constructed in-place." << std::endl;
auto tuple = std::make_tuple(MoveMe{10});
std::cout << std::endl << "Other tests." << std::endl;
std::tuple<MoveMe> tuple2 = std::tuple<MoveMe>(MoveMe{10});
std::cout << std::endl << "Moved." << std::endl;
MoveMe obj{10};
auto tuple3 = std::make_tuple(std::move(obj));
std::exit(0);
// return 0;
}
Outputs
Constructed in-place.
Destroyed
Other tests.
Destroyed
Moved.
Any ideas why that is? My understanding of rvalues is basic, so my guess is I'm missing something obvious. Thank you.
It isn't copied it is still moved.
In your case, you're creating a temporary (MoveMe{10}
) that is then used to move construct the instance of MoveMe
in the tuple. After the instance of MoveMe
in the tuple is move constructed, the temporary that was moved is destroyed.
You can directly construct the MoveMe
object in the tuple by forwarding the arguments
std::cout << "Directly Constructed" << std::endl;
auto tuple = std::tuple<MoveMe>(10);
Which will not result in a temporary being created then destroyed.