In this snippet, I allocate a local object B that I pass to the constructor of another object C which takes it as a rvalue reference. I then put the latter into a container.
When I retrieve C and static_cast its member back to B, the value is incorrect (and valgrind identifies 18 errors!)
#include <iostream>
#include <memory>
#include <vector>
class A {
public:
virtual ~A() {};
};
class B: public A {
public:
B(int foo) : _foo(foo) {}
int _foo;
};
class C {
public:
C(A&& a): _a(std::move(a)) {}
A&& _a;
};
std::vector<C> v;
void bar() {
v.emplace_back(B(12));
}
int main() {
bar();
C&& c = std::move(v.front());
std::cout << static_cast<B&&>(c._a)._foo << std::endl;
return 0;
}
My understanding is that, as C takes a rvalue reference, there should not be any object slicing. I should still be able to retrieve a full B object. Additionally, my understanding (most probably flawed) of std::move
is that I can 'move' a local variable out of its context and that by taking a rvalue reference, C takes ownership of B.
The output is 39931504
instead of 12
.
Anyone could explain to me what is going on?
I should still be able to retrieve a full B object.
You would be if it wasn't a temporary that does not exist by the moment control reaches bar
's closing brace. You hold a reference in your C
and a reference to a temporary object can quickly become dangling.
A quick fix is to simply change C
's member declaration into std::unique_ptr<A> a;
and properly initialise it, say, as
template<class AChild> C(AChild child)
: a(std::make_unique<AChild>(std::move(child))) {};
(add SFINAE by taste).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With