Reputation: 4666
Is there a way to avoid copying 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);
}
Upvotes: 3
Views: 314
Reputation: 1879
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.
Upvotes: 0
Reputation: 477040
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
}
}
Upvotes: 1
Reputation: 392954
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.
Upvotes: 1
Reputation: 2441
One way is to store only pointers to the base class like this:
vector<Base*> v(100);
v.push_back(new Derived());
doStuff(v);
Upvotes: 0
Reputation: 31647
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.
Upvotes: 2
Reputation: 5019
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!
Upvotes: 0