简体   繁体   中英

using *void as a buffer for static_cast

So I go this:

class A;

class B : public A;

class C : public B;

vector<A*> *vecA;

vector<C*> *vecC;

And I want to cast a vectC into a vecA.

vector<A*> *_newA = static_cast< vector<A*>* >(vecC); //gives an error

So I used void pointer as a buffer and the cast:

void *buffer = vecC;

vector<A*> *_newA = static_cast< vector<A*>* >(buffer); //works

Is this valid? Is there another way to do it?

You should just have a std::vector<A*> and then when you wish to put a B or C inside, you can do this:

 std::vector<A*> vec;
 vec.push_back(b);

This will work much better than anything you're currently doing.

Also, you should use std::unique_ptr or std::shared_ptr , depending on ownership semantics of your pointers. Owning raw pointers are a no-no!!

Is this valid?

No it's not. It is completely undefined what happens if you access it.

Is there another way to do it?

Yes. It depends on what you want to do:

  1. copy the content: std::copy(vecC.begin(), vecC.end(), std::back_inserter(vecA));

  2. create an adaptor which behaves as random access container of A* if given a container or iterator of C* or any other derived type

  3. I am sure there are other solutions, just tell us what you want to do

It looks to me as if you're looking for covariant support for generic (template) types. This is not supported at all by C++. It is supported by the CLR - and C#/VB - though only in the latest versions.

In spite of this, to echo others' responses, you're likely barking up the wrong tree. My hunch is that you want to have a vector of pointers to A-typed objects... and this type should include virtual methods and a virtual destructor - as necessary. It's impossible to be more specific about a suitable alternative approach without a better understanding of the high-level problem you're trying to solve - which is not evident from your question.

The magic words you probably needed to know are "covariance" and "contravariance". Have a look here for a very closely related issue.

Short answer: there's no neat, sensible way to do the conversion you want to do merely with casts. You will need to copy to contents of your old vector the long way into your new vector.

But more importantly: 1. Don't ever use new on a standard container type. 2. Don't pass around pointers to standard container types. 3. Don't pass around raw pointers to your own objects, use std::shared_ptr instead.

Instead of detouring via void* , with C++11 just use reinterpret_cast .

However, the conversion that you desire permits very ungood things :

#include <iostream>
#include <vector>
using namespace std;

class Base {};

class Derived: public Base
{ public: int x; Derived(): x(42) {} };

int main()
{
    vector< Derived* >  v;
    Derived             d;

    v.push_back( &d );
    cout << v.back()->x << endl;        // 42

    vector< Base* >*    pbv =
        reinterpret_cast< vector< Base* >* >( &v );
    Base                b;

    pbv->push_back( &b );
    cout << v.back()->x << endl;        // indeterminate value
}

It's roughly the same issue that you have with converting T** to T const** (not permitted, could allow ungood things). The short of it is, don't do this unless you know exactly what you're doing. The longer of it, hm, well, there's not room to discuss it here, but it involves differentiating between mutable and immutable collections, and being very very careful.


edit: as others (who did not address the conversion question) have already stated, a practical solution is a vector of A pointers, or smart pointers, and then using C++ polymorphism (ie virtual member functions).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM