pop_back() 返回值?

pop_back() return value?

提问人:Parvinder Singh 提问时间:9/26/2012 最后编辑:GriwesParvinder Singh 更新时间:12/25/2021 访问量:42556

问:

为什么没有返回值?我已经对此进行了谷歌搜索,发现它使它更有效率。这是在标准中这样做的唯一原因吗?pop_back()

C++ 向量

评论


答:

5赞 Zdeslav Vojkovic 9/26/2012 #1

那么,必须有多少个原因呢?

这样可以避免在只想从容器中删除对象时对对象进行可能代价高昂的复制。C++的理念是不为不需要的东西付费。

评论

0赞 sbi 9/26/2012
我认为这是错误的。请参阅我对 Ravindra 回答的评论
3赞 Zdeslav Vojkovic 9/27/2012
好吧,我很确定与异常相关的问题可能是原因之一,但我也很确定这是另一个原因。我还没有看到任何证据表明这种设计与性能问题无关(因为移动语义是一个相当新的东西),我也没有声称没有另一个(好吧,我的第一句话可能听起来像这样,但它旨在澄清为什么一个理由是不够的)。Sutter在“异常C++”中声称,“这样做的一个原因:它避免了削弱异常安全性。
2赞 sbi 9/27/2012
“我还没有看到任何证据表明这种设计与性能问题无关。你还没有看到任何证据表明这种设计与香蕉无关。所以?是你提出了一个主张(“这是关于性能的!”),是我挑战了这一点。因此,您需要支持索赔。
3赞 Zdeslav Vojkovic 9/27/2012
好吧,你让我在那里工作:)斯特鲁斯特鲁普在“C++ prog. lang”[16.3.5]中说: .OTOH,Josuttis的书也提到了嘉吉纸。我的结论是性能原因之一,而我并不认为这是唯一的原因。然而,在阅读了所有的参考资料后,我也同意例外安全可能是决定这种方式的更重要因素。It just pops, and if we want to know what was on the top of the stack before pop, we must look. This happens not to be my favorite style of stack, but it's arguably more efficient and it's the standard
0赞 user1095108 12/25/2021
这是最好的答案,为什么不避免不必要的复制呢?
-1赞 Puppy 9/26/2012 #2

为什么它会返回该值?在弹出该值之前,您始终可以随时访问该值 - 无需提供此功能。pop_back

评论

1赞 Nawaz 9/26/2012
-1.它没有回答这个问题。为什么不返回值是有原因的,这篇文章没有讨论这个理由。pop_back
1赞 Puppy 9/26/2012
它没有理由存在这一事实是它不存在的一个很好的理由,这确实回答了这个问题。
6赞 sbi 9/26/2012
@DeadMG:我相信有一个很好的可用性案例 pro 返回一个值。传统上,这就是堆栈的 pop 函数的作用。不,原因纯粹是为了例外安全。pop_back()
66赞 yves Baumes 9/26/2012 #3

我认为复制最后一个对象的实例可能会引发异常这一事实有关。这样做时,您将丢失对象,因为 pop_back() 确实将其从容器中删除。最好用几行代码:

std::vector<AnyClass> holds = {...} ;
try {
  const AnyClass result = holds.pop_back(); // The copy Ctor throw here!
} catch (...)
{ 
 // Last value lost here. 
}

评论

14赞 hansmaad 9/26/2012
+1 无法实现异常安全 (gotw.ca/gotw/008.htmT container<T>::pop())
6赞 Nawaz 9/26/2012
+1 这是正确答案。它告诉我们导致这种无返回值设计的基本原理。pop_back
1赞 yves Baumes 9/27/2012
右。我(还)对 c++11 还不了解。但我想答案仍然成立。我的意思是,不是使用编译器提供的移动控制,而是使用用户定义的移动控制。此外,afaik,我记得在某处读到过,一个类可以被定义为逃避任何移动 ctor(= 删除?如果是这样,那么我们回到复制 ctor 的情况下(如果提供了,否则我想使用向量不会编译)。
1赞 sehe 9/27/2012
如果我没记错的话,@DeadMG移动构造函数可能也不是noexcept
2赞 Nawaz 9/27/2012
@DeadMG:移动复制,这取决于值的类型,因为不是每个类型都是可移动的,而且移动也可能引发异常。
19赞 Abyx 9/26/2012 #4

这是因为命令-查询分离原则

8赞 mkaes 9/26/2012 #5

效率是一回事。不返回元素的另一个原因是异常安全。
如果函数返回了该值,并且复制构造函数引发了异常,则可能无法保证容器处于与调用之前相同的状态。
pop_back()pop()pop()

您可以在 Herb Sutters 书籍中找到有关异常的更多信息。我认为这里涵盖了这个话题。但我不确定。

评论

4赞 sbi 9/26/2012
问题不在于容器被更改,问题在于对象可能被删除,但你还没有把它拿回来——所以它丢失了。
76赞 sbi 9/26/2012 #6

效率与它几乎没有关系(或者说根本没有关系)。

这个设计是汤姆·嘉吉(Tom Cargill)在90年代发表的一篇重要论文的成果,该论文在当时引起了不少人的注意。IIRC在嘉吉公司中表明,不可能设计出一个异常安全堆栈弹出功能。

评论

5赞 yves Baumes 9/26/2012
+1 参考 Tom Cargill 论文“Excpetion handling: a false sense of security”。必读。:-)
2赞 Konrad Rudolph 9/26/2012
如果我没记错的话,那么“C++语言”或“有效C++”的某些版本实际上声称这是出于效率原因,因为他们当时还没有弄清楚移动构造和NRVO。
0赞 sbi 9/26/2012
@Konrad:AFAIR,迈耶斯甚至指着嘉吉的论文。(想想看,我敢打赌,这就是它存在副本的真正原因,在 Pearson 的网站上。
0赞 Mikhail 4/28/2014
我们如何确定已删除的对象不会抛出析构函数?我知道它不应该,但是我们怎么能控制它呢?
7赞 sbi 5/5/2014
@Mikhail:如果析构函数抛出,你不能保证任何事情。这就是他们不能这样做的原因。再说一遍:析构函数绝不能抛出。时期。如果你写了一个允许转义异常的 dtor,你也可以取消引用 。NULL
7赞 Seppo Enarvi 9/26/2012 #7

原因与其说是效率,不如说是异常安全。容器类可用于存储任何类型的对象。如果函数在从容器中删除对象后返回对象,则不可能以异常安全的方式实现 pop_back(),因为返回对象的值涉及复制构造。

这是 vector::p op_back() 在 GNU C++ 标准库中的实际实现:

  void
  pop_back()
  {
    --this->_M_impl._M_finish;
    this->_M_impl.destroy(this->_M_impl._M_finish);
  }

如果它最终返回最后一个元素,它会是什么样子:

  value_type
  pop_back()
  {
    value_type save = back();
    --this->_M_impl._M_finish;
    this->_M_impl.destroy(this->_M_impl._M_finish);
    return save;
  }

这涉及两个复制构造,分别在语句和返回对象副本时。不能保证在从容器中销毁元素后,返回表达式不会引发异常。save = back()

0赞 user1095108 12/25/2021 #8

在计算机编程中,正交性意味着操作发生变化 只做一件事,不影响他人。

pop_back()只做一件事,它不复制,因此它是正交的。