快速背景
我是一名Java开发人员,在我的免费/无聊时间里一直在玩C ++。
前言
在C ++中,您经常会看到pop通过引用参数:
void pop(Item& removed);
我知道用你删除的内容“填写”参数会很好。这对我来说完全有意义。这样,要求删除顶部项目的人可以查看删除的内容。
但是,如果我在Java中这样做,我会做这样的事情:
Item pop() throws StackException;
这样,在pop之后我们返回:结果为NULL,一个Item或一个异常将被抛出。
我的C ++教科书向我展示了上面的例子,但我看到很多堆栈实现没有参数(例如stl stack)。
问题
应该如何在C ++中实现pop函数?
奖金
为什么呢?
答案 0 :(得分:26)
回答这个问题:你不应该在C ++中实现pop函数,因为它已经由STL实现了。 std::stack
容器适配器提供方法top
以获取对堆栈顶部元素的引用,并使用方法pop
来移除顶部元素。请注意,仅pop
方法不能用于执行这两个操作,正如您所询问的那样。
为什么要这样做?
top
负责一项责任,pop
负责另一项责任。任何希望获取元素副本的代码都可以免费获得:
Foo f(s.top());
s.pop();
此外,this discussion可能很有趣。
如果要实现pop来返回值,那么无论是按值返回还是将其写入out参数都无关紧要。大多数编译器实现RVO,它将优化按值返回的方法,与copy-into-out-parameter方法一样高效。请记住,其中任何一个都可能比使用top()或front()检查对象效率低,因为在这种情况下绝对没有复制完成。
答案 1 :(得分:4)
Java方法的问题是它的pop()
方法至少有两个影响:删除一个元素,然后返回一个元素。这违反了软件设计的单一责任原则,这又为设计复杂性和其他问题打开了大门。它还意味着性能损失。
在STL方式中,有时候你pop()
对弹出的项目不感兴趣。你只想要删除顶部元素的效果。如果函数返回元素并忽略它,那么这就是浪费的副本。
如果你提供两个重载,一个接受引用而另一个不引用,那么你允许用户选择他(或她)是否对返回的元素感兴趣。通话的表现最佳。
STL不会使pop()
函数重载,而是将它们分成两个函数:back()
(或top()
适配器的std::stack
)和{ {1}}。 pop()
函数只返回元素,而back()
函数只删除它。
答案 2 :(得分:1)
使用C ++ 0x会使整个事情再次变得困难。
作为
stack.pop(item); // move top data to item without copying
可以有效地从堆栈中移动顶部元素。而
item = stack.top(); // make a copy of the top element
stack.pop(); // delete top element
不允许这样的优化。
答案 3 :(得分:0)
我可以在C ++中看到使用此语法的唯一原因:
void pop(Item& removed);
如果您担心发生不必要的副本。
如果您返回Item
,则可能需要该对象的其他副本,可能贵。
实际上,C ++编译器非常擅长复制省略,并且几乎总是实现返回值优化(通常即使在禁用优化的情况下进行编译),这使得这一点没有实际意义,甚至可能意味着简单的“按值返回”在某些情况下,版本变得更快。
但是如果你进入过早优化(如果你担心)编译器可能不会优化副本,即使在实践中它将做到这一点) ,您可以通过分配参考参数来争辩“返回”参数。
更多信息here
答案 4 :(得分:0)
IMO,C ++中Java pop
函数等效的良好签名就像:
boost::optional<Item> pop();
使用选项类型是返回可能可用或不可用的内容的最佳方式。