【问题标题】:Returning a vector of unique_ptr from function从函数返回一个 unique_ptr 向量
【发布时间】:2012-08-31 10:15:32
【问题描述】:

我目前正在阅读《Head First Object Oriented Analysis and Design》一书,同时也习惯了 C++11 的一些特性(尤其是 unique_ptr 和 move 语义)。在书中,他们以策略棋盘游戏的设计为例。它有一个板,瓷砖和瓷砖上的单位。代码是用 Java 编写的,我试图用 C++ 重写它。在Java中,tile类如下:

public class Tile
{
    private List units;

    public Tile()
    {
        units = new LinkedList();
    }

    protected void addUnit(Unit unit)
    {
        units.add(unit);
    }

    protected List getUnits()
    {
        return units;
    }
}

我首先在 c++ 中使用 shared_ptr 做了同样的事情。与我使用原始指针的第二个版本相比,它工作但非常慢。然后我尝试了 unique_ptr:

class Tile
{

public:
  Tile();
  virtual ~Tile();

  void addUnit()
  {
    mUnits.push_back(std::unique_ptr<Unit>(new Unit());
  }

  std::vector<std::unique_ptr<Unit>> getUnits()
  {
    return mUnits;
  }

private:
  std::vector<std::unique_ptr<Unit>> mUnits;

};

编译器不喜欢 getUnits。据我了解,它来自于复制构造函数在 unique_ptr 中被禁用的事实。你将如何返回向量列表? 谢谢!

【问题讨论】:

  • 引用返回:std::vector&lt;std::unique_ptr&lt;Unit&gt;&gt;&amp; getUnits()
  • 返回一个 unique_ptrs 向量意味着放弃它们,因此 Tile 不再可以访问它们。这就是你想要的吗?
  • 你真的需要返回向量吗?如果你的类包装了std::vector,你应该提供比这个访问器更好的对其数据的访问。这个例子清楚地表明,从 Java 到 C++ 的不费吹灰之力的重写不是要走的路。尤其是因为您没有提供任何新功能。
  • 别忘了,Java“对象”是指针;即使看起来像按值返回,结果也指向原始对象。 C++ 中的类比是返回一个指针或引用。
  • 原来的类无论如何设计都很糟糕,希望那本书能提到这一点。为什么封装一个容器只是为了提供对它的完全访问权限?

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


【解决方案1】:

在 C++ 中返回的值会产生一个副本 - 如果这是您想要的,您不能使用 unique_ptr 或必须手动复制和 std::move 它。但是,我认为您只想提供对Units 的访问权限(无论出于何种原因......),所以只需返回一个引用:

std::vector<std::unique_ptr<Unit>> const& getUnits() const
{
  return mUnits;
}

const 仅在您不想授予向量写入权限时才需要。)

现在,仍然有几个问题出现:为什么是~Tile virtual?我看没必要。

你为什么使用 owning ptr 来指向单位?在原始 Java 代码中,您获得了对外部单元的引用,并且只存储了一个引用 - 如果 Java 代码中的 Tile 被破坏,则单元不会(据我所见),只要它们是在别处引用。为了在 C++ 中实现完全相同,您使用 shared_ptr 是正确的。

当然,您可以明确 是单位的真正所有者并进行相应操作 - 如果它不是 Tile,请使用原始指针。另见"Which kind of pointer do I use when?"

【讨论】:

  • ~Tile() 是虚拟的,因为 Java 代码具有 protected 方法,这意味着其目的是从该方法派生类。
  • Funny... 我尝试了 auto test = getUnits() 但我收到一个错误:“使用已删除的函数 'std::unique_ptr 等 :-(
  • @darkman:嗯..auto x = init; 会导致复制发生。使用auto&amp; x = init;
  • 为什么这在 Visual Studio 2013 中不起作用?我仍然在尝试访问复制构造函数时遇到编译器错误...
  • 在 "auto& x = init;" 中,Xeo 在 auto 之后使用 & 来指定 x 是对 init 的左值引用。点击此处了解更多详情:open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html
猜你喜欢
  • 2011-05-18
  • 1970-01-01
  • 1970-01-01
  • 2015-04-16
  • 2022-10-21
相关资源
最近更新 更多