pop_back()返回值?

Par*_*ngh 50 c++ vector

为什么没有pop_back()返回值?我用Google搜索了这一点,发现它使它更有效率.这是在标准中做到这一点的唯一原因吗?

sbi*_*sbi 58

效率几乎没有(或者没有,真的)与它有关.

这个设计是汤姆·卡吉尔(Tom Cargill)在90年代出版的一篇重要论文的结果,当时引起了不少人的关注.IIRC,Cargill在其中展示了设计异常安全堆栈弹出功能是不可能的.

  • @Mikhail:如果破坏者抛出,你无法保证任何东西.这就是他们不能这样做的原因.再说一遍:___架构师绝不能扔掉.Period .___如果你编写一个允许转义异常的dtor,你也可以解除引用`NULL`. (6认同)
  • +1参考Tom Cargill论文"Excpetion handling:a false sense of security".必读.:-) (5认同)
  • 如果我没记错的话,“The C++ Language”或某些版本的“Effective C++”实际上声称这是出于效率原因,因为他们当时还没有弄清楚移动构造和 NRVO。 (2认同)

yve*_*mes 52

我认为有一些事情与复制最后一个对象的实例可能会引发异常有关.这样做时,你丢失了你的对象,因为pop_back()确实从容器中删除了它.使用几行代码更好:

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

  • +1`T container <T> :: pop()`无法实现异常安全(http://www.gotw.ca/gotw/008.htm) (13认同)
  • +1这是正确的答案.它告诉我们导致这种"pop_back"设计没有返回值的基本原理. (5认同)
  • @DeadMG:*move*或*copy*,取决于*type*的值,因为不是每个类型都是可移动的,加上*move*也可能抛出异常. (2认同)

mka*_*aes 6

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

您可以在Herb Sutters书籍中找到有关例外情况的更多信息.我认为这里涉及这个主题.但我不确定.

  • 问题不在于容器是否已更改,问题是对象可能已被删除,但您还没有将其取回 - 因此它已丢失. (3认同)

Zde*_*vic 5

那么,有多少个理由呢?

当您只想从容器中删除对象时,这可以避免潜在的昂贵的对象复制。C++ 的理念是不为不需要的东西付费。

  • 好吧,我很确定与异常相关的问题很可能是*一个*原因,但我也很确定这是另一个原因。我还没有看到任何证据表明这种设计与性能问题无关(因为移动语义是一个相当新的事物),并且我没有声称没有其他设计(好吧,我的第一句话可能听起来像那样,但是这是为了澄清为什么一个原因还不够)。Sutter 在《Exceptional C++》中声称“这样做的*一个*理由是:它避免了削弱异常安全性。”。 (3认同)
  • 好吧,你让我在那里工作:) Stroustrup 在《C++ prog》中说道。lang' [16.3.5]: `它只是弹出,如果我们想知道弹出之前堆栈顶部有什么,我们必须查看。这恰好不是我最喜欢的堆栈风格,但它可以说更高效,并且是标准。OTOH,Josuttis 书中也提到了嘉吉纸。我的结论是,性能是原因之一,但我并不认为这是唯一的原因。然而,在阅读所有参考资料后,我也同意异常安全可能是决定这种方式的更重要因素。 (3认同)
  • “我还没有看到任何证据表明这种设计与性能问题无关。” 您还没有看到任何证据表明该设计与香蕉无关。_所以?_是你提出了主张(“这与性能有关!”),是我对此提出了质疑。所以你需要支持这一主张。 (2认同)

Sep*_*rvi 5

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

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

  void
  pop_back()
  {
    --this->_M_impl._M_finish;
    this->_M_impl.destroy(this->_M_impl._M_finish);
  }
Run Code Online (Sandbox Code Playgroud)

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

  value_type
  pop_back()
  {
    value_type save = back();
    --this->_M_impl._M_finish;
    this->_M_impl.destroy(this->_M_impl._M_finish);
    return save;
  }
Run Code Online (Sandbox Code Playgroud)

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