有没有办法将std :: vector <const T*>转换为std :: vector <T*>而无需额外的分配?

Ser*_*tin 13 c++ stl vector c++11

假设我有Storage一些Objects有一个聚合指向Objects某个向量中的指针的方法.像这样:

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
}
Run Code Online (Sandbox Code Playgroud)

通常,有一种方法可以避免在const +非const方法对的实现中使用copy-paste,方法是在其他方面使用它们调用其中一个const_cast.然而,这是不可能的,因为方法的返回类型是不同的.

避免复制粘贴的最直接的方法是const从非const版本调用版本并使用返回std::vector<const T*>来填充单独的版本std::vector<T*>.但是,这将导致至少2个堆分配(每个向量一个).我想避免与第二个向量相关的分配.

我想知道是否有办法写出类似的东西

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

因此,允许写

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));
}
Run Code Online (Sandbox Code Playgroud)

std::vector(std::unique_ptr例如)中没有"释放"方法允许转移内存所有权 - 并且由于一个很好的理由,所以我希望这是不可能的.

我也明白,如果可能的话,通常应该避免危险的操作,就像这样const_cast.但在这种情况下仔细使用似乎比复制粘贴更有益.

编辑:添加了对'额外'分配的含义的澄清,并更改Storage::aggregate_objects()Storage::aggregate_some_objects()更好地表明这些方法的实现比基于范围的循环更复杂 - 因此希望避免复制粘贴实现.

Sam*_*hik 13

最简洁的答案是不.std::vector<Object*>并且std::vector<const Object*>是两个不同的独立课程.他们彼此不同的class A距离class B.人们通常认为,仅仅因为它们都是从它们开始的std::vector,它们在某种程度上是彼此相关的.这不是真的,因此没有办法将一个转换为另一个,"到位".这些向量类中的每一个都拥有它们相应的内部data(),并且不会愿意将它放到其他一些奇怪的类中.

答案仍然很长,但在许多情况下,可以解决这个问题,以避免手动代码重复.事实是,在大多数情况下,代码重复是不可避免的,可以做的最好的事情就是避免手动代码重复.

一种常见的方法是使常量和可变类方法成为单个共享私有模板的外观:

// Header file:

class Storage {

public:

    std::vector<const Object*> aggregate_objects() const;

    std::vector<Object*> aggregate_objects();

private:

    template<typename v_type> void make_aggregate_objects(v_type &v) const;
};

// In the translation unit:

template<typename v_type> void Storage::make_aggregate_objects(v_type &v) const
{
     // Now, create 'v' here... v.reserve(), v.push_back(), etc...
}

std::vector<const Object*> Storage::aggregate_objects() const
{
     std::vector<const Object *> v;

     make_aggregate_objects(v);

     return v;
}

std::vector<Object*> Storage::aggregate_objects()
{
     std::vector<const Object *> v;

     make_aggregate_objects(v);

     return v;
}
Run Code Online (Sandbox Code Playgroud)

编译器仍然会生成两个几乎完全相同的代码块,但至少不是你在做所有的输入.

另一种类似的方法是将lambda传递给模板函数而不是传递一个vector对象,私有模板函数使用lambda函数作为回调来构造返回的向量.通过一些类型的擦除和一些帮助std::function,私有类方法可以转换为普通方法,而不是模板方法.