【发布时间】:2016-10-12 08:31:13
【问题描述】:
假设我有一些Objects 的Storage,它有一个方法可以聚合指向向量中一些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
}
一般来说,在实现 const + non-const 方法对时,有一种方法可以避免复制粘贴,方法是在 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;
}
因此,允许写入
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));
}
std::vector(例如std::unique_ptr)中没有允许转移内存所有权的“释放”方法——这是有充分理由的,所以我认为这是不可能的。
我也明白,如果可能的话,这将是一个通常应该避免的危险操作,就像const_cast一样。但在这种情况下谨慎使用似乎比复制粘贴更有益。
编辑: 澄清了“额外”分配的含义,并将Storage::aggregate_objects() 更改为Storage::aggregate_some_objects(),以更好地表明这些方法的实现比基于范围的方法更复杂循环 - 因此希望避免复制粘贴实现。
【问题讨论】:
-
您的函数按值返回,因此每次都分配一个新向量。您要避免哪些“额外分配”?
-
是的,函数按值返回,这意味着必须发生至少一个堆分配(最好的情况——我知道返回向量的大小,可以调用
vector::reserve)。我正在谈论将在不涉及复制粘贴的相关方法的最简单实现中发生的分配:非const版本调用const版本(返回std::vector<const T*>)并填充一个单独的@ 987654341@。创建一个单独的向量将导致至少 1 个(“额外”)分配,这是我想避免的。在问题中澄清了这一点。 -
如果你的目标只是避免复制函数体,那么不要试图用强制转换和未定义的行为做任何愚蠢的事情,只需编写一个返回
std::vector<T*>的函数模板,然后用 @ 调用它987654343@ ==Object或T==const Object。