为什么没有pop_back()
返回值?我对此进行了谷歌搜索,发现它可以提高效率。这是在标准中这样做的唯一原因吗?
8 回答
效率与它几乎没有关系(或者根本没有关系)。
这个设计是汤姆嘉吉在 90 年代发表的一篇重要论文的成果,当时引起了很多人的注意。IIRC,在其中嘉吉表明不可能设计一个异常安全的堆栈弹出功能。
我认为与复制最后一个对象的实例可能会引发异常这一事实有关。这样做时,您将丢失对象,因为 pop_back() 确实将其从容器中删除。用几行代码更好:
std::vector<AnyClass> holds = {...} ;
try {
const AnyClass result = holds.pop_back(); // The copy Ctor throw here!
} catch (...)
{
// Last value lost here.
}
这是因为命令-查询分离原则。
效率是一回事。pop_back()
不返回元素的另一个原因是异常安全。
如果pop()
函数返回值,并且复制构造函数抛出异常,则您可能无法保证容器与调用之前的状态相同pop()
。
您可以在 Herb Sutters 书籍中找到有关异常的更多信息。我认为这个话题已经涵盖在这里。但我不确定。
原因与其说是效率不如说是异常安全。容器类可用于存储任何类型的对象。如果函数在从容器中删除对象后返回对象,则不可能以异常安全的方式实现 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()
语句处和在返回对象副本时。无法保证在元素从容器中销毁后返回表达式不会引发异常。
那么,有多少理由呢?
当您只想将其从容器中删除时,这可以避免潜在的昂贵的对象复制。C++ 的理念是不为不需要的东西付费。
在计算机编程中,正交性意味着操作只改变一件事而不影响其他事情。
pop_back()
只做一件事,它不复制,因此它是正交的。
为什么它会返回值?您始终可以在弹出它之前随时访问该值 - 无需pop_back
提供此功能。