为什么pop()会参与争论?

Ste*_*ano 9 c++ java stack

快速背景
我是一名Java开发人员,在我的免费/无聊时间里一直在玩C++.

前言
在C++中,您经常会看到pop通过引用获取参数:

void pop(Item& removed);
Run Code Online (Sandbox Code Playgroud)

我知道用你删除的内容"填写"参数会很好.这对我来说完全有意义.这样,要求删除顶部项目的人可以查看删除的内容.

但是,如果我在Java中这样做,我会做这样的事情:

Item pop() throws StackException;
Run Code Online (Sandbox Code Playgroud)

这样,在pop之后我们返回:结果为NULL,Item或异常将被抛出.

我的C++教科书向我展示了上面的例子,但是我看到很多堆栈实现没有参数(例如stl stack).

问题
如何在C++中实现pop函数?

奖金
为什么?

Dan*_*Dan 26

回答这个问题:你不应该在C++中实现pop函数,因为它已经由STL实现了.所述std::stack容器适配器提供的方法top获得的堆栈顶部的元素的引用,并且所述方法pop以除去顶部元件.请注意pop,正如您所询问的那样,单独的方法不能用于执行这两个操作.

为什么要这样做呢?

  1. 异常安全: Herb Sutter对GotW#82中的问题给出了很好的解释.
  2. 单一责任原则:在GotW#82中也提到过. top照顾一个责任,pop照顾另一个.
  3. 不支付你不需要的东西:对于一些代码,可能就足够了检查顶级元素,然后弹出它,从来没有将这个元素的(潜在的昂贵)的副本.(这在SGI STL文档中有提及.)

任何希望获得元素副本的代码都可以免费获得:

Foo f(s.top());
s.pop();
Run Code Online (Sandbox Code Playgroud)

此外,这个讨论可能很有趣.

如果您要实现pop来返回值,那么无论是按值返回还是将其写入out参数都无关紧要.大多数编译器都实现了RVO,它将优化返回值方法,使其与copy-into-out-parameter方法一样高效.请记住,其中任何一个都可能比使用top()或front()检查对象效率低,因为在这种情况下绝对没有复制完成.

  • + 1 ......但也许"如果你用C++实现pop函数,你应该遵循标准的容器接口." (2认同)

wil*_*ell 5

Java 方法的问题在于它的pop()方法至少有两个效果:删除元素和返回元素。这违反了软件设计的单一职责原则,进而为设计复杂性和其他问题打开了大门。它还意味着性能损失。

在 STL 的方式中,想法是有时当您pop()对弹出的项目不感兴趣时​​。您只想要删除顶部元素的效果。如果函数返回该元素而您忽略它,那么这就是浪费的副本。

如果您提供两个重载,一个重载接受引用,另一个重载则不接受,那么您允许用户选择他(或她)是否对返回的元素感兴趣。通话性能将达到最佳。

STL 不会重载pop()函数,而是将它们分成两个函数:(back()top()在适配器的情况下std::stack)和pop()。该back()函数仅返回该元素,而该pop()函数仅删除该元素。

  • 作为单个原子操作具有两种效果的函数并不违反软件设计的单一职责原则。 (4认同)
  • 单一职责原则涉及系统中类或组件的职责,而不是方法的效果。你知道,你可能会把设计原则看得太过分。 (3认同)
  • @Dave 有多少理由需要更改删除并返回元素的函数“pop()”?如果你可以计算多个,那么它就违反了单一责任原则。 (2认同)