捕获第一个异常后,为什么外部临时变为空?
int main(){ std :: string temp(“exception”); int值; while(std :: cin>> value&& …
我不确定它是否是另一个答案中提到的错误,但不知何故catch块在处理异常一次后改变/省略了temp的内容。下面的代码解决了这个问题。制作 temp 一个 const 解决这个问题。
temp
const
#include <iostream> int main() { const std::string temp("exception"); int value; while(std::cin>> value && value != 0) { try{ if(value > 9) throw temp; else std::cout << value << "\n"; } catch(std::string temp){ std::cerr << temp << "\n"; } } return 0; }
这似乎是GCC实施复制省略的一个错误。 C ++标准说明如下:
的 [class.copy.elision] 强> (强调我的) 复制/移动操作的省略,称为复制省略,是 在下列情况下允许(可以合并到 消除多份副本): 在throw-expression中,当操作数是非易失性自动对象的名称时(函数或catch子句除外) 参数) 的 其范围不超出范围 最里面的封闭try-block(如果有的话) 强> ,复制/移动 从操作数到异常对象的操作可以省略 将自动对象直接构造到异常对象中 在以下复制初始化上下文中,可能会执行移动操作 用来代替复制操作: 如果throw-expression的操作数是非易失性自动对象的名称(函数或catch子句参数除外) 的 其范围不会超出最内层封闭try-block的末尾(如果有的话) 强> ,
的 [class.copy.elision] 强> (强调我的)
复制/移动操作的省略,称为复制省略,是 在下列情况下允许(可以合并到 消除多份副本):
在以下复制初始化上下文中,可能会执行移动操作 用来代替复制操作:
这是一系列优化,允许避免或尽可能有效地完成异常对象的复制初始化。现在,常见的实现 std::string 移动构造是将源字符串留空。这似乎正是您的代码所发生的事情。该 temp 在外部范围内移动(并留空)。
std::string
但这不是预期的行为。的范围 temp 你扔了 超过 (到目前为止)它被抛入的尝试块。所以GCC没有业务应用复制省略。
一个可能的解决方法是放置声明 temp 在 - 的里面 while 环。这初始化了一个新的 std::string 对象每次迭代,所以即使 GCC 从它移动,它不会引人注目。
while
GCC
评论中提到了另一种解决方法,即制作外部 temp 一个const对象。这将强制复制(因为移动操作需要非const源对象)。