Consider the following piece of code
#include <algorithm>
#include <iostream>
#include <memory>
#include <vector>
struct Base {
int x;
Base(int x) : x(x) {}
};
struct Derived : public Base {
int y, z;
Derived(int x) : Base(x), y(x + 1), z(x + 2) {}
};
void update(const std::vector<std::shared_ptr<const Base>>& elements) {
for (const auto elem : elements) {
std::cout << elem->x << "\n";
}
}
int main(int, char**) {
std::vector<std::shared_ptr<Derived>> elements(4);
{
int ctr = 0;
std::generate(begin(elements), end(elements), [&ctr]() { return std::make_shared<Derived>(++ctr); });
}
// update(elements); // note: candidate function not viable: no known conversion from 'vector<shared_ptr<Derived>>' to 'const vector<shared_ptr<const Base>>' for 1st argument
update(reinterpret_cast<std::vector<std::shared_ptr<const Base>>&>(elements)); // ok
return 0;
}
My question is if using reinterpret_cast
to cast from std::vector<std::shared_ptr<Derived>>
to std::vector<std::shared_ptr<const Base>>&
is feasible and accepted by standard.
I have compiled the code with clang-3.8 and gcc-6.1 with -fsanitize=undefined
and it looks like it's ok. However, I seem unable to find a proper explanation on cppreference.
Of course I can easily create an appriopriate function but it's longer than one-line reinterpret_cast and requires a temporary vector.
void update(const std::vector<std::shared_ptr<Derived>>& elements) {
std::vector<std::shared_ptr<const Base>> casted(elements.size());
std::copy(begin(elements), end(elements), begin(casted));
update(casted);
}
Templates in general and containers (I treat shared_ptr
as a special form of container) are not covariant in C++. This means that if you have two types Base
and Derived < Base
and a template<typename T> class X {};
, X<Base>
and X<Derived>
are two completely different things and not in any form of relationship.
In your case, you have an object of type std::vector<std::shared_ptr<Derived>>
and then create a std::vector<std::shared_ptr<const Base>>&
which is then used to access it. I think this has two issues:
vector
into a reference type. I really wonder why this works.If you compile your code with gcc -fstrict-aliasing
, the compiler will assume that your program is compliant with the rule and optimize it. It will generate a warning:
> Start prog.cc: In function 'int main(int, char**)': prog.cc:33:80:
> warning: dereferencing type-punned pointer will break strict-aliasing
> rules [-Wstrict-aliasing]
> update(reinterpret_cast<std::vector<std::shared_ptr<const Base>>&>(elements)); // ok
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