【发布时间】:2012-09-26 11:06:47
【问题描述】:
为什么pop_back() 没有返回值?我对此进行了谷歌搜索,发现它可以提高效率。这是在标准中这样做的唯一原因吗?
【问题讨论】:
为什么pop_back() 没有返回值?我对此进行了谷歌搜索,发现它可以提高效率。这是在标准中这样做的唯一原因吗?
【问题讨论】:
效率与它几乎没有关系(或根本没有关系)。
这个设计是 an important paper by Tom Cargill 的成果,发表于 90 年代,当时引起了很多人的注意。 IIRC,在其中嘉吉表明不可能设计一个异常安全的堆栈弹出功能。
【讨论】:
NULL。
我认为复制最后一个对象的实例可能会引发异常这一事实与此有关。这样做时,您将丢失对象,因为 pop_back() 确实将其从容器中删除。几行代码就更好了:
std::vector<AnyClass> holds = {...} ;
try {
const AnyClass result = holds.pop_back(); // The copy Ctor throw here!
} catch (...)
{
// Last value lost here.
}
【讨论】:
T container<T>::pop()无法实现异常安全 (gotw.ca/gotw/008.htm)
pop_back 没有返回值的设计的基本原理。
noexcept,如果我没记错的话
【讨论】:
效率是一回事。 pop_back() 不返回元素的另一个原因是异常安全。
如果pop()函数返回值,拷贝构造函数抛出异常,则可能无法保证容器与调用pop()之前的状态相同。
您可以在 Herb Sutters 书籍中找到有关异常的更多信息。我认为该主题已涵盖here。但我不确定。
【讨论】:
原因与其说是效率不如说是异常安全。容器类可用于存储任何类型的对象。如果函数在从容器中删除对象后返回对象,则不可能以异常安全的方式实现 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++ 的理念是不为不需要的东西买单。
【讨论】:
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。 OTOH,Josuttis 的书也提到了嘉吉的论文。我的结论是性能是的原因之一,但我并不声称这是唯一的原因。但是,在阅读所有参考资料后,我也同意异常安全可能是决定这种方式的更重要因素。
在计算机编程中,正交性意味着操作会发生变化 只做一件事,不影响其他人。
pop_back() 只做一件事,它不复制,因此它是正交的。
【讨论】:
为什么它会返回值?您始终可以在弹出之前随时访问该值 - pop_back 无需提供此功能。
【讨论】:
pop_back 不返回值是有原因的,这篇文章没有讨论这个原因。
pop_back() 返回一个值。传统上,这就是堆栈的弹出函数所做的。不,原因纯粹是为了异常安全。