【问题标题】:C++ designing containers and managing list returnC++ 设计容器和管理列表返回
【发布时间】:2010-11-25 14:50:56
【问题描述】:

我正在开发一个作为另一个类的容器的类。在容器类中,我必须实现一个方法来获取集合中的所有元素。我的容器类使用 std::deque。

我应该返回对双端队列的引用吗? 我应该返回双端队列的副本吗? (我的上帝告诉我这不是答案...... :)) 我应该返回一个数组吗? ... 在这种情况下,最佳做法是什么? 谢谢

【问题讨论】:

  • 问问自己为什么需要访问容器类之外的内部对象。您可能正在破坏封装。也许您可以添加一个方法,允许您通过传入一个函数来修改每个内部对象?

标签: c++ containers return


【解决方案1】:

恕我直言,最佳做法是使用 iterator design pattern 并返回迭代器

就您的特定示例而言,我会这样做:

class myContainer
{
public: 
   typedef std::deque<X> actual_container_type;
   typedef actual_container_type::iterator iterator;
   typedef actual_container_type::const_iterator const_iterator;
   //etc...

   iterator begin() {return cont.begin(); }
   const_iterator begin() const {return cont.begin(); }
   iterator end() {return cont.end(); }
   const_iterator end() const {return cont.end(); }

   //you may choose to also provide push_front and push_back... or whatever :)


  private:
     actual_container_type cont;
}

【讨论】:

  • 在您的情况下,您返回的迭代器是来自现有 STL 类的迭代器。返回他们自己的迭代器的用户应该从 std::iterator 派生他们的类,以便它获取属性和 typedef。如果迭代器是指针,则无需这样做。
  • 谢谢,有道理。现在我可以更好地移动并清楚地看到......谢谢:)
  • 啊,抱歉,有一件事......编译器如何知道我何时收集迭代器 begin() 或 const_iterator begin()?
  • @Andry:如果在 const 对象上调用该函数,则将调用 const 版本,否则将调用非常量版本。不要忘记成员函数的对象参数(this)也参与重载决议,而 MyContainer& 和 const MyContainer& 是不同的类型(为了重载决议)
  • 啊,是的,好的,现在很多事情都变得更好了 :) 好吧,好的,我明白了在 c++ 中是如何处理引用的,但仍然不明白一件事:考虑有 void f(int&)和 void g(const int&),Bruce Eckel 在 Thinking in C++ 2nd edition 中告诉我调用 f(1) 是错误的,而编译器在请求 g(1) 时不会出现问题。为什么会发生这种情况?
【解决方案2】:

只需将begin()end()size()operator[] 包装起来就可以了。

【讨论】:

  • 是的,谢谢,这是 c++ 中的一种常见模式,:) 很明显我不是专家... :) 但只有一个问题:编译器如何知道我何时整理迭代器 begin() 或 const_iterator begin()?
  • 这取决于上下文,如果你的对象是const,它会调用const_iterator begin() const;请注意,重载的是最右边的 const,而不是返回类型。
【解决方案3】:

迭代器模式很好,但你暴露了你的实现细节。它可能会被滥用并破坏您的班级内部。这些对于 API 来说都是坏事,您应该设计针对这种情况的保护措施。

这听起来很浪费,但最安全的方法是将集合的副本作为 std::vector 返回。

【讨论】:

  • 但是 const_iterator 无论如何都会为复制的 std::vector 上的 const_iterator 提供相同的输出,对吧? (除非在此期间修改了数据,但随后所有的赌注都被取消了......)我的观点是不会对内部造成伤害。只是不要公开非常量迭代器。
  • const_iterator 没问题。但是,如果您更改集合的实现,您可能会遇到问题,即如果您将集合更改为地图,则不要期望您的迭代器能够像它们那样工作。正如您所指出的,从另一个线程修改数据将使迭代器无效,您不一定知道。复制是最安全的!
猜你喜欢
  • 2013-08-03
  • 2011-10-17
  • 1970-01-01
  • 2017-12-19
  • 2013-06-10
  • 1970-01-01
  • 2012-03-19
  • 2011-07-20
  • 1970-01-01
相关资源
最近更新 更多