C++ 返回值?

C++ 返回值?,c++,vector,C++,Vector,为什么pop_back()没有返回值?我在谷歌上搜索了一下,发现这会让它更高效。这是在标准中这样做的唯一原因吗?那么,有多少原因呢 这避免了在您只想将对象从容器中删除时对其进行昂贵的复制。C++有一种哲学,即不为你不需要的东西付出代价。在弹出该值之前,您可以随时访问该值-无需弹出返回即可提供此功能。我认为这与复制最后一个对象的实例可能引发异常有关。这样做时,您将丢失对象,因为pop_back()确实将其从容器中删除。使用几行代码更好: std::vector<AnyClass> ho

为什么
pop_back()
没有返回值?我在谷歌上搜索了一下,发现这会让它更高效。这是在标准中这样做的唯一原因吗?

那么,有多少原因呢


这避免了在您只想将对象从容器中删除时对其进行昂贵的复制。C++有一种哲学,即不为你不需要的东西付出代价。在弹出该值之前,您可以随时访问该值-无需
弹出返回
即可提供此功能。

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

std::vector<AnyClass> holds = {...} ;
try {
  const AnyClass result = holds.pop_back(); // The copy Ctor throw here!
} catch (...)
{ 
 // Last value lost here. 
}
std::vector holds={…};
试一试{
const AnyClass result=holds.pop_back();//复制构造函数抛出到这里!
}捕获(…)
{ 
//最后一个值在这里丢失。
}

这是因为效率。

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

你可以在Herb Sutters的书中找到更多关于异常的信息。我想这个话题已经涵盖了。但我不确定。

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


这个设计是90年代出版的一本书的成果,当时它引起了很多人的关注。在IIRC中,Cargill证明了设计异常安全的堆栈pop函数是不可能的

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

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

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

+1
t container::pop()
无法实现异常安全()+1这是正确的答案。它告诉我们导致这种没有返回值的
pop_back
设计的基本原理。对。我对c++11还不是很了解。但我想答案仍然是正确的。我的意思是,不是使用编译器提供的move-ctor,而是用户定义的。此外,我还记得在某个地方读到过这样一篇文章:一个类可能被定义为避开任何移动向量(=删除?)。如果是这样,那么我们回到copy-ctor的情况(如果提供了这样的情况,否则我猜使用向量将无法编译)。@DeadMG-move构造函数也可能不是
noexcept
,如果我不是mistaken@DeadMG:移动或复制,这取决于值的类型,因为并非所有类型都是可移动的,加上移动也可能引发异常。-1。它没有回答这个问题。为什么
pop\u back
不返回值是有道理的,而这篇文章并没有讨论这个道理。它没有存在的理由是它不存在的一个很好的理由,这确实回答了这个问题。@DeadMG:我相信有一个很好的可用性案例pro
pop\u back()
返回值。传统上,堆栈的pop函数就是这样做的。不,原因纯粹是为了例外安全。+1用于参考Tom Cargill的论文“例外处理:错误的安全感”。必须阅读的内容。:-)如果我记得正确的话,“C++语言”或一些版本的“有效C++”实际上声称是出于效率的原因,因为他们没有找到移动构造和NRVO。于是,康拉德:AfAIR,迈尔斯甚至指向卡吉尔的论文。(仔细想想,我敢打赌这就是皮尔逊网站上存在副本的真正原因。)我们如何确保移除的对象不会抛出析构函数?我知道不应该,但我们怎么能控制它?@Mikhail:如果破坏者抛出,你不能保证任何事情。这就是他们不能这样做的原因。再次声明:析构函数决不能抛出。时期如果您编写了一个允许转义异常的dtor,那么您也可以取消引用
NULL
。问题不是容器被更改了,而是对象可能被删除了,但您没有将其取回-因此它丢失了。我相信这是错的。好吧,我很确定与异常相关的问题可能是原因之一,但我也很确定这是另一个原因。我还没有看到任何证据表明这种设计与性能问题无关(因为移动语义是一个全新的事物),我也没有声称没有其他的(好吧,我的第一句话听起来可能是这样的,但它是为了澄清为什么一个理由是不够的)。Sutter在“exception C++”中声称,“这样做有一个原因:它可以避免削弱异常安全性。”“我还没有看到任何证据表明这种设计与性能问题无关。”你也没有看到任何证据表明这种设计与香蕉无关。所以是你提出了要求(“这是关于性能的!”),是我提出了质疑。所以你需要支持这个声明。好吧,你让我在那里工作:)Stroustrup在《C++程序》中说。lang'[16.3.5]:
它只是弹出,如果我们想知道在弹出之前堆栈顶部有什么,我们必须查看。这恰好不是我最喜欢的堆栈样式,bu