开发者

Howto avoid copying when casting a vector<Derived*> to a vector<Base*>

开发者 https://www.devze.com 2023-04-07 06:50 出处:网络
Is there a way to avoid c开发者_如何转开发opying large vectors, when a function expects a vector with (pointer to) baseclass objects as input but I only have a vector of (pointers to) derived objects?

Is there a way to avoid c开发者_如何转开发opying large vectors, when a function expects a vector with (pointer to) baseclass objects as input but I only have a vector of (pointers to) derived objects?

class Base {};

class Derived : public Base {};

void doStuff(vector<Base*> &vec)
{
    //do stuff with vec objects
}

int main()
{
    vector<Derived*> fooDerived(1000000);

    vector<Base*> fooBase(fooDerived.begin(), fooDerived.end()); // how to avoid copying here?
    doStuff(fooBase);
}


If you could use a vector<Derived*> as if it where a vector<Base*>, you could add a pointer to a class OtherDerived : public Base to that vector. This would be dangerous.


You can't cast the vectors. However, you shouldn't really need to either.

If you really want, you could use Boost Iterator (documentation)

static Derived* ToDerived(Base* b)
{
    return dynamic_cast<Derived*>(b); // return null for incompatible subtypes
}

static void DoSomething(Derived* d)
{ 
          if (!d)
               return; // incompatible type or null entry
          // do work
}


// somewhere:
{
    std::vector<Base*> bases;

    std::for_each(
         boost::make_transform_iterator(bases.begin(), &ToDerived),
         boost::make_transform_iterator(bases.end(), &ToDerived),
         DoSomething);
}

Note: a particularly handy effect of using dynamic_cast<Derived*> is that if the runtime type of the object cannot be casted to Derived* (e.g. because it is actually an OtherDerived*, it will simply return a null pointer.


If your definition of doStuff() is absolutely mandatory, then you won't get around the copy. Containers of pointers aren't "covariant" with respect to the pointee's class hierarchy, for a whole host of reasons. (For example, if you could treat vector<Derived*> like a vector<Base*>, you could insert Base-pointers into it which wouldn't behave like Derived-pointers. In any event, the parameter type of a container is fixed and part of the container's type.)

If you do have some leeway with the function, you could restructure the code a bit: You could make it a template parametrized on the container, or a template on an iterator range, and/or you could split the actual workload into a separate function. For example:

void doStuffImpl(Base *);

template <typename Iter>
void doStuff(Iter begin, Iter end)
{
  for (Iter it = begin; it != end; ++it)
  {
    doStuffImpl(*it);  // conversion happens here
  }
}


Since your template for the vector is a pointer, your fooBase local variable is going to be using reference. Maybe the question is not very clear, if you could specify clearly we may try to address the problem!


One way is to store only pointers to the base class like this:

vector<Base*> v(100);
v.push_back(new Derived());

doStuff(v);


I found this topic interesting where they mention you can safely cast Derived* to Base* (but not the other side) while this is not possible from vector<Derived*> to vector<Base*> but you kind of should be able to... (Ok, the address of the vector changes, thus needing a copy)
One dirty solution they mention is using reinterpret_cast<vector<Base*> >(vector<Derived*>) but not sure if it's better then using the copy constructor... probably the same thing happens.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号