Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it ok to cast a STL container with Base type to Derived type?

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.

like image 744
Morpheus Avatar asked Mar 28 '11 14:03

Morpheus


3 Answers

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);
}
like image 66
Flexo Avatar answered Sep 27 '22 21:09

Flexo


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
}
like image 38
Tim Avatar answered Sep 27 '22 23:09

Tim


This is not ok. Templated types with different Ts 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.

like image 29
Mark B Avatar answered Sep 27 '22 22:09

Mark B