unique_ptr类型的Vector,继承

vector of unique_ptr, inheritance?

本文关键字:Vector 继承 类型 ptr unique      更新时间:2023-10-16

假设代码如下:

class Parent {}
class Child : public Parent {}
static std::vector<std::unique_ptr<Child>> Foo();

有没有更简单的方法来写这个函数:

std::vector<std::unique_ptr<Parent>> Bar() {
  auto children = Foo();
  std::vector<std::unique_ptr<Parent>> parents;
  result.insert(result.end(), std::make_move_iterator(children.begin()),
                std::make_move_iterator(children.end()));
  return parents;
}

这行不通:

std::vector<std::unique_ptr<Parent>> Bar() {
  return Foo(); // Compiler error: cannot convert from vector<...> to vector<...>
}

类型不同。Foo()返回std::vector<std::unique_ptr<Child>>, Bar()返回std::vector<std::unique_ptr<Parent>>。这是无法规避的。然而,与其:

std::vector<std::unique_ptr<Parent>> Bar() {
    auto children = Foo();
    std::vector<std::unique_ptr<Parent>> parents;
    result.insert(result.end(), std::make_move_iterator(children.begin()),
                std::make_move_iterator(children.end()));
    return parents;
}

你可以这样做:

std::vector<std::unique_ptr<Parent>> Bar() {
    auto tmp = Foo();
    return {std::make_move_iterator(tmp.begin()), std::make_move_iterator(tmp.end()));}
}

我们可以在其他地方写样板文件:

templace<class Cin>
struct move_from_c{
  Cin* c;
  template<class Cout>
  operator Cout()&&{
    using std::begin; using std::end;
    return {std::make_move_iterator(begin(*c)), std::make_move_iterator(end(*c))};
  }
};
template<class C, class dC=std::remove_reference_t<C>>
move_from_c<dC> move_from(C&&c){
  return {std::addressof(c)};
}

你的函数是:

std::vector<std::unique_ptr<Parent>> Bar() {
  return move_from(Foo());
}

这将Bar的实现细节与业务逻辑分开。(搬离的方式和搬离的决定是分开的)

几个"更简单"的方法:

#include <algorithm>
#include <iterator>
std::vector<std::unique_ptr<Base>> f1(std::vector<std::unique_ptr<Derived>> v)
{
    std::vector<std::unique_ptr<Base>> result;
    result.reserve(v.size());
    std::move(v.begin(), v.end(), std::back_inserter(result));
    return result;
}
std::vector<std::unique_ptr<Base>> f2(std::vector<std::unique_ptr<Derived>> v)
{
    return {std::make_move_iterator(v.begin()), std::make_move_iterator(v.end())};
}

建议使用句柄/句体习语,并将多态性作为句柄类的实现细节来实现。

这为您提供了值语义(适用于容器),并且还允许您轻松实现关系操作符:

#include <vector>
#include <memory>
class ParentImpl {
public:
  virtual ~ParentImpl() = default;
  virtual void foo() {}
};
class ChildImpl : public ParentImpl {};
class ParentHandle
{
public:
  using ptr_type = std::unique_ptr<ParentImpl>;
  // construct from ptr_type
  ParentHandle(ptr_type ptr = nullptr) : ptr_(std::move(ptr_)) {}
  // public interface defers to polymorphic implementation
  void foo()
  {
    ptr_->foo();
  }
private:
  std::unique_ptr<ParentImpl> ptr_;
};
static std::vector<ParentHandle> Foo()
{
  std::vector<ParentHandle> result;
  result.emplace_back(std::make_unique<ParentImpl>());
  result.emplace_back(std::make_unique<ChildImpl>());
  return result;
}