【问题标题】:How to copy vector<unique_ptr<T>> to independent vector<T*>如何将向量<unique_ptr<T>> 复制到独立向量<T*>
【发布时间】:2016-06-21 16:34:06
【问题描述】:

我有一个std::vector&lt;std::unique_ptr&lt;T&gt;&gt; vec1,其中 T 是一个抽象类型。我想创建std::vector&lt;T*&gt; vec2,其中第二个向量的指针指向的对象是第一个向量的指针指向的对象的副本。

例如:*(vec1[0]) == *(vec2[0])vec1[0].get() != vec2[0] ...等等...

怎么做?

【问题讨论】:

  • 到底是什么问题?你不知道如何从unique_ptr 获取底层指针?还是别的什么?
  • @SergeyA。我知道从std::unique_ptrget() 方法)获取原始指针很热。但是如果我将它推到 vec2 则 vec2 将不会独立于 vec1。来自 vec1 的指针将指向与来自 vec2 的指针相同的内存位置。我需要对象的副本。
  • 为什么?​​​​​​​​​​​这是一个巨大的代码气味。 C API 采用T** 和所有权? :(
  • @BarryTheHatchet 是的,我知道这很糟糕,但我需要这个“hack”(在 ut 测试中)。
  • 打赌你不是真的 :)

标签: c++ c++11 vector smart-pointers unique-ptr


【解决方案1】:

使用std::transform

std::vector<T*> vec2;
vec2.reserve(vec1.size()); // optimization to avoid reallocations, it isn't necessary, and without it the code still works correctly
std::transform(vec1.begin(), vec1.end(), std::back_inserter(vec2), [](const std::unique_ptr<T>& p){ return YourCloneFunction(*p); }

编写克隆函数的一种方法是让所有后代类都定义虚拟clone 函数,该函数在T 中是抽象的。该方法的代码很简单,但需要为每个Derived类定义。

class T
{
    virtual std::unique_ptr<T> clone() const = 0;
    virtual ~T(){}
};

class Derived : public T
{
    std::unique_ptr<T> clone() const override {
        return std::unique_ptr<T>(new Derived(*this));
    }
};

这样,代码就变成了

std::vector<T*> vec2;
vec2.reserve(vec1.size()); // optimization to avoid reallocations, it isn't necessary, and without it the code still works correctly
std::transform(vec1.begin(), vec1.end(), std::back_inserter(vec2), [](const std::unique_ptr<T>& p){ return p->clone().release(); }

请注意,我们有 vec2 原始指针指向不属于任何智能指针的对象。这很糟糕,除非您将 vec2 传递给拥有这些指针所有权的旧函数。

否则,如果您只想要副本的std::vector&lt;T*&gt; 视图,请克隆到中间std::vector&lt;std::unique_ptr&lt;T&gt;&gt;,然后将每个实例上.get() 的结果复制到std::vector&lt;T*&gt;

【讨论】:

  • 因为它是一个副本,你应该表现出良好的行为,在转换之前调用适当大小的保留
  • 你为什么要屈服于这种需求?真的没有理由在这里打电话给reserve
  • @milleniumbug。谢谢。
【解决方案2】:

手动方式:

std::vector<std::unique_ptr<T>> vec1;
std::vector<T*> vec2;
vec2.reserve(vec1.size()); // optimization to avoid reallocations

for (const auto& e : vec1) {
    vec2.push_back(e->clone());
}

virtual T* T::clone() const

【讨论】:

  • 因为它是一个副本,你应该表现出良好的行为,在循环之前调用适当大小的保留
  • @galop1n,没必要。
  • "T 是一个抽象类型",这意味着你不能构造T 本身的新实例。
  • @SergeyA:没必要,但完全合适。
猜你喜欢
  • 2015-10-03
  • 1970-01-01
  • 2013-01-13
  • 2014-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-07
相关资源
最近更新 更多