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