samedi 11 juin 2016

Is there a way to convert std::vector<const T*> to std::vector<T*> without extra allocations?


Let's say I have a Storage of some Objects which has a method that aggregates pointers to some of the Objects in a vector. Like this:

class Storage
{
public:
   std::vector<Object*> aggregate_some_objects(); // non-const version
   std::vector<const Object*> aggregate_some_objects() const; // const version

private:
   std::unordered_map<size_t, Object> m_objects; // data is stored 
                                                 // by-value in a non-vector container
}

Generally, there is way to avoid copy-paste in implementation of const + non-const method pairs by calling one of them inside the other with the help of const_cast. Here however this is not possible because the return types of the methods are different.

The most straightforward way to avoid copy-paste here would be to call const version from a non-const version and use the returned std::vector<const T*> to populate a separate std::vector<T*>. However this would lead to at least 2 heap allocation (one for each vector). I would like to avoid the allocations associated with the second vector.

I wonder if there is way to write something like

template <typename T>
std::vector<T*> remove_const_from_vector_of_ptrs(std::vector<const T*>&& input)
{
   std::vector<const T*> ret;
   // do some magic stuff here that does not involve
   // more memory allocations
   return ret;
}

Thus, allowing to write

std::vector<const Object*> Storage::aggregate_some_objects() const
{
   // non-trivial implementation
}

std::vector<Object*> Storage::aggregate_some_objects() 
{
   auto objects = const_cast<const Storage*>(this)->aggregate_some_objects();
   return remove_const_from_vector_of_ptrs(std::move(objects));
}

There is no 'release' method in std::vector (like std::unique_ptr for example) that allows transferring of memory ownership - and for a very good reason, so I expect that this is not possible.

I also understand that if it were possible, it would be a dangerous operation that should be generally avoided, just as const_cast. But a careful usage in cases like this seems more beneficial than copy-pasting.


Aucun commentaire:

Enregistrer un commentaire