假设我有一个 Storage
一些 Object
s 有一个聚合指向 Objects
的指针的方法在一个 vector 中。像这样:
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 个堆分配(每个 vector 一个)。我想避免与第二个 vector 相关的分配。
我想知道是否有办法写类似的东西
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()
为了更好地表明这些方法的实现比基于范围的循环更复杂 - 因此希望避免复制粘贴实现。
最佳答案
简短的回答是:不。 std::vector<Object*>
和 std::vector<const Object*>
是两个不同的、独立的类。它们彼此不同,如 class A
来自 class B
.人们常常认为,仅仅因为它们都以 std::vector
开头,它们在某种程度上彼此相关。这不是真的,因此没有办法“就地”将一个转换为另一个。这些 vector 类中的每一个都拥有它们相应的内部data()
,并且不会心甘情愿地把它交给其他一些奇怪的类(class)。
答案仍然是否定的,但在许多情况下,可以解决此问题以避免手动重复代码。事实上,在大多数此类情况下,代码重复是不可避免的,而能做的最好的事情就是避免手动重复代码。
一种常见的方法是让常量和可变类方法成为单个共享私有(private)模板的外观:
// 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;
}
编译器仍然会生成两个几乎相同的代码块,但至少不是你来做所有的输入。
另一种类似的方法是将 lambda 传递给模板函数,而不是传递 vector 对象,而私有(private)模板函数使用 lambda 函数作为回调来构造返回的 vector 。通过一些类型删除,以及来自 std::function
的一些帮助,私有(private)类方法可以变成普通方法,而不是模板方法。
关于c++ - 有没有办法将 std::vector<const T*> 转换为 std::vector<T*> 而无需额外分配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37764052/