【问题标题】:Throw temporary instead of local variable - why?抛出临时变量而不是局部变量 - 为什么?
【发布时间】:2018-11-21 12:50:25
【问题描述】:

有问题的代码是这样的:

struct something_bad_happened_exception : std::exception {};

void foo() {
    something_bad_happened_exception e;
    throw e;
}

clang 发出警告,内容如下:

Throw 表达式应该抛出匿名临时值 [cert-err09-cpp]

这意味着foo()应该改为:

void foo() {
    throw something_bad_happened_exception();
}

为什么抛出一个临时变量而不是一个局部变量更好?

【问题讨论】:

  • @StoryTeller 我已经看到了,但没有解释,只是触发警告的详细信息。
  • 严格来说,在你的情况下,这似乎是一个愚蠢的警告,一个真正的误报。
  • 所以警告的目的是警告抛出诸如实例变量之类的东西?如果是,这可能是答案...
  • 如果e 的复制构造函数可以抛出(例如,如果e 有一个std::string 成员变量)会有区别

标签: c++


【解决方案1】:

根据throw expression 上的cpp 参考:

首先,从表达式复制初始化异常对象(这可能会调用右值表达式的移动构造函数,并且复制/移动可能会受到复制省略)

因此,如果您的代码完美无缺,但将调用复制构造函数,这在效率方面可能是不可取的。不过,copy elision 可能会发生,如果(强调我的)

以下情况,允许编译器但不要求省略副本

[省略]

在 throw 表达式中,当操作数是具有自动存储持续时间的非易失性对象的名称时,该对象不是函数参数或 catch 子句参数,并且其范围不超过最里面的 try-块(如果有尝试块)。

例如,考虑下面的代码

#include <exception>
#include <iostream>

struct something_bad_happened_exception : std::exception {
  something_bad_happened_exception(const something_bad_happened_exception& r) {
     std::cout << "A copy has occoured!" << std::endl;
  }
  something_bad_happened_exception() { }
};

int main()
{
  std::cout << "First throw" << std::endl;
  try {
    const something_bad_happened_exception e;
    throw e;
  }
  catch (const std::exception& ex)
    {
      std::cout << "Caught exception" << std::endl;
    }
  std::cout << "Second throw" << std::endl;
  try {
    throw something_bad_happened_exception();
  }
  catch (const std::exception& ex)
    {
      std::cout << "Caught exception" << std::endl;
    }

  return 0;
}

使用gcc 8.2.1clang 6.0 编译代码,使用选项-O3 输出为

First throw
A copy has occoured!
Caught exception
Second throw
Caught exception

第一个throw 对应于您的示例。即使e 的副本可以被省略,gccclang 都不会实现复制省略。

第二个throw有一个匿名临时,不会发生复制。

【讨论】:

    【解决方案2】:

    代码不符合样式检查器检查的“throw only anonymous temporaries”(注意选项CheckThrowTemporaries)的约定。

    就“按值抛出”约定而言,该约定和该检查过于严格-在这方面,示例程序符合要求。一个真正不符合标准的例子是抛出一个指向对象的指针。

    【讨论】:

      猜你喜欢
      • 2012-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-20
      相关资源
      最近更新 更多