62

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

4

8 回答 8

68

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

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

于 2012-09-26T11:16:15.250 回答
58

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

std::vector<AnyClass> holds = {...} ;
try {
  const AnyClass result = holds.pop_back(); // The copy Ctor throw here!
} catch (...)
{ 
 // Last value lost here. 
}
于 2012-09-26T11:12:23.197 回答
17

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

于 2012-09-26T11:13:32.487 回答
6

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

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

于 2012-09-26T11:14:37.373 回答
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);
  }

如果它最后返回最后一个元素,这就是它的样子:

  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()语句处和在返回对象副本时。无法保证在元素从容器中销毁后返回表达式不会引发异常。

于 2012-09-26T11:17:43.610 回答
3

那么,有多少理由呢?

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

于 2012-09-26T11:11:05.810 回答
0

在计算机编程中,正交性意味着操作只改变一件事而不影响其他事情。

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

于 2021-12-25T13:04:31.863 回答
-1

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

于 2012-09-26T11:11:41.617 回答