std::vector<A> something
is a vector which dynamically allocates storage for A
, and only A
, when objects are added.
The storage type of the vector is A
, it stores instances of A
.
When you push the first C
onto it, it does something along the lines of:
void push_back(const A& a) // NOTE: A, not C, downcasting occurs
{
// extreme aproximation
if (something.begin_ == nullptr) {
something.begin_ = new A;
something.begin_[0] = a; // A::operator=(const A&);
something.capacity_ = something.end_ = something.begin_ + 1;
} else {
..
}
}
Because C
inherits from A
it is able to downcast to this. However, it is only going to copy the A
portion of the object passed to it, because the storage type of the vector is A
and so your int bar
in C
is not copied.
This is called slicing, and the only way around it is either dynamic (pointers or std::any), or the perilous path of using a union.
-- Edit --
A secondary issue is what you expect std::vector<A> &&bar
to do? The temporary objects to which it references expires at the end of the constructor expression:
B b{1, vector<A>{C{1},C{2}}}; // temporary vector is destroyed
// b.bar is dangling rvalue reference
-- Edit 2 --
Your question title contains "use move semantics" but as mentioned in edit 1, you only store an rvalue reference. Move semantics are about transferance: consider this simple strdup
wrapper:
struct Strdupper {
char* str_;
Strdupper() = delete;
Strdupper(const char* str) : str_(strdup(str)) {}
~Strdupper() { if (str_) free(str_); }
Strdupper(const Strdupper& rhs) { str_ = strdup(rhs.str_); }
Strdupper(Strdupper&& rhs) str_(rhs.str_) { rhs.str_ = nullptr; }
Strdupper& operator=(const Strdupper& rhs) { if (str_) free(str_); str_ = strdup(rhs.str_); return *this; }
Strdupper& operator=(Strdupper&& rhs) { std::swap(str_, rhs.str_); return *this; }
// ...
};
Instead of an rvalue reference, your class B needs to actually store the vector and std::move
the input parameter value to its constructor to call it's move-constructor:
class B {
std::vector<X> vec_;
public:
B() = default;
B(const std::vector<X>& vec) : vec_(vec) {} // copy semantics
B(std::vector<X>&& vec) : vec_(std::move(vec)) {} // move semantics
};