尝试阻塞影响封闭范围中的变量


阿政ღ
2025-03-12 01:14:04 (9天前)


捕获第一个异常后,为什么外部临时变为空?

include< iostream>

int main()
{
std :: string temp(“exception”);
int值;
while(std :: cin>> value&& …

3 条回复
  1. 0# 那月静好 | 2019-08-31 10-32



    我不确定它是否是另一个答案中提到的错误,但不知何故catch块在处理异常一次后改变/省略了temp的内容。下面的代码解决了这个问题。制作

    temp

    一个

    const

    解决这个问题。



    1.   #include <iostream>
    2. int main()
    3. {
    4.     const std::string temp("exception");
    5.     int value;
    6.     while(std::cin>> value && value != 0)
    7.     {
    8.          try{
    9.               if(value > 9) throw temp;
    10.               else std::cout << value << "\n";
    11.             }
    12.          catch(std::string temp){
    13.               std::cerr << temp << "\n";
    14.               }
    15.     }
    16.     return 0;
    17. }
    18. </code>

  2. 1# 夏花 | 2019-08-31 10-32



    这似乎是GCC实施复制省略的一个错误。 C ++标准说明如下:





    [class.copy.elision]
    </强>
    (强调我的)



    复制/移动操作的省略,称为复制省略,是
    在下列情况下允许(可以合并到
    消除多份副本):




    • 在throw-expression中,当操作数是非易失性自动对象的名称时(函数或catch子句除外)
      参数)

      其范围不超出范围
      最里面的封闭try-block(如果有的话)
      </强>
      ,复制/移动
      从操作数到异常对象的操作可以省略
      将自动对象直接构造到异常对象中



    在以下复制初始化上下文中,可能会执行移动操作
    用来代替复制操作:




    • 如果throw-expression的操作数是非易失性自动对象的名称(函数或catch子句参数除外)

      1. 的<strong>
      2. 其范围不会超出最内层封闭try-block的末尾(如果有的话)
      3. </强>
      4. </LI>
      5. </UL>



    这是一系列优化,允许避免或尽可能有效地完成异常对象的复制初始化。现在,常见的实现

    std::string

    移动构造是将源字符串留空。这似乎正是您的代码所发生的事情。该

    temp

    在外部范围内移动(并留空)。



    但这不是预期的行为。的范围

    temp

    你扔了

    超过

    (到目前为止)它被抛入的尝试块。所以GCC没有业务应用复制省略。



    一个可能的解决方法是放置声明

    temp

    在 - 的里面

    while

    环。这初始化了一个新的

    std::string

    对象每次迭代,所以即使

    GCC

    从它移动,它不会引人注目。



    评论中提到了另一种解决方法,即制作外部

    temp

    一个const对象。这将强制复制(因为移动操作需要非const源对象)。


登录 后才能参与评论