Reputation: 1750
Is it ok to cast a STL container from Base type to Derived type ? For example, I have two vectors. First one is in type of a Base class, second is in type of a Derive class.
class Base
{
// Code
};
class Derive : public Base
{
// Code
};
Usage
vector<Base*>* vec_base = new vector<Base*>;
// Add some Derive type data to vec_base
vector<Derive*>* vec_derive = (vector<Derive*>*)(vec_base);
// Using elements as Derive pointers. Works fine.
Is this ok ? (It works fine, but I wanted to get some comments about this). Thank you very much.
EDIT: Updating according to the answers.
Say, If I use that vector carefully, and will not use with multiple-inheritance and will not insert objects other than Derive type, is it ok ? (I guess, it is not)
And thank you very much for the answers.
Upvotes: 5
Views: 2758
Reputation: 9179
The safer way to do this is using std::transform.
But, since inside the implementation of std::list, T=Base* or T=Derived* behaves the same way (both have the same size), a list has same inner structure than a list. So it is possible to do the following trick:
vector<Derived*> vector2 = *( reinterpret_cast< vector<Derived*>* >(&vector1) );
Note: My answer is informational, please stick with the std::transform approach. I am not sure if in STDC++ implementation others than GCC's the vector behave the same way, ie. I am not sure if the assertion "list< Base* > and list< Derivated*> have the same inner structure" is true in others implementations.
Upvotes: 0
Reputation: 88711
This is definitely not ok, and is one of the examples of c-style casts masking errors. "It works for me" is not indicative of well defined behaviour in this instance.
If you really want to do this I'd suggest:
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
class Base
{
// Code
virtual ~Base();
};
class Derrive : public Base
{
// Code
};
Derrive *convert(Base * in) {
// assert here?
return dynamic_cast<Derrive*>(in);
}
int main() {
vector<Base*>* vec_base = new vector<Base*>;
// Add some Derrive type data to vec_base
vector<Derrive*>* vec_derrive = new vector<Derrive*>;
transform(vec_base->begin(), vec_base->end(), back_insert_iterator<vector<Derrive*> >(*vec_derrive), convert);
}
Upvotes: 9
Reputation: 9172
You are doing a c-style cast, which is essentially doing a reinterpret_cast
, which tells the compiler "treat x like y from now on, and just trust me that it works". So it will definitely compile, but is a bad idea. There is no type safety here, and it may work some of the time, but will crash unpredictably at other times.
What you can do instead:
for (unsigned int i=0; i < vec_base->length(); i++)
{
Derrive* d = dynamic_cast<Derrive*> (vec_base[i]);
if (d ) {
// this element is a Derrive instance, so we can treat it like one here
}
// else, skip it, log an error, throw an exception, whatever,
// this element in the vector is not of type Derrive
}
Upvotes: 2
Reputation: 96241
This is not ok. Templated types with different T
s are unrelated types (even though they both say std::vector
, and using a C-style cast just lets you get away with undefined behavior.
If it seems to work for now, consider yourself unlucky that it didn't crash.
If you know that ALL the items in the vector are the derived class then just make the vector point to derived objects up front. If you don't know that, then the cast isn't safe.
Upvotes: 1
Reputation: 190945
No. That won't work well.
Say I have Derrive2
that derives from Base
. I can put that in the STL container, but it won't safely cast to Derrive
.
Upvotes: 0