【问题标题】:Throwing exception from member constructor (brace initializer vs initializer list)从成员构造函数中抛出异常(大括号初始值设定项与初始值设定项列表)
【发布时间】:2018-02-21 15:39:23
【问题描述】:

我对成员对象初始化期间(从构造函数)抛出异常时会发生什么失去了信心(可能是 2 小时)。

让我给你看个例子:

int init (int f) {
    throw f;
}

struct X {
    X (int f) : n {init (f)} {}
    int n;
};

struct P {
    X x {20};
};

及用法:

int main (int argc, char** argv) {
    try {
        P p {};
    }
    catch (int n) {
        std::cout << n << "\n";
    }
}

这段代码(C++11 模式)编译良好(使用 GCC 7.2.1)并在 Linux(Centos 7.4.1708)下编译:

terminate called after throwing an instance of 'int'
[1]    1242 abort (core dumped)  ./main

问题是:为什么? 为什么catch() 部分没有被收录?

我已经跟踪了这个问题,这意味着当我的 P 班级看起来有点不同时:

struct P {
    P (int f) : x {f} {}
    X x;
};

并以这种形式初始化p 对象:P p {20} 结果是:20,这是预期的,没有核心转储

有人能解释一下在异常情况下使用 brace-or-equal-initializermember-initializer-list 初始化成员有什么区别吗?

错误报告:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85363

【问题讨论】:

  • 有趣的是,使用-std=c++11 编译代码会产生您提到的结果,但使用c++14c++17 看起来一切都很好。
  • 对我来说似乎是一个编译器错误。考虑到 JBL 的发现,并且代码在 c++11 模式下的 clang++ 中运行良好。而且我认为程序没有任何问题
  • 是的,在coliru with clang and c++11工作
  • 我可以用 VS2015 重现这个。添加P() {} 允许捕获异常,但P() = default; 没有帮助。 std::is_nothrow_default_constructible&lt;P&gt;::value; 似乎是 true,这是一个问题。在决定默认构造函数的noexceptness 时,似乎没有考虑默认成员初始化器。
  • @FrançoisAndrieux 这很奇怪。 std::is_nothrow_default_constructible&lt;P&gt;::value;false in g++,即使它确实无法捕获。

标签: c++


【解决方案1】:

两者之间应该没有实际区别:

struct P {
    X x {20};
};

struct P {
    P() : x{20} { }
    X x;
};

但是对于 C++11 模式(但不是 C++14 或更高版本)有一个 GCC bug 会导致 p{} 的初始化发生在 try 块之外,或者将 noexcept 的等效项添加到隐式定义的默认构造函数 P.

【讨论】:

  • 自从 OP 报告了我认为它已经在 cmets 中链接到的错误,但显然没有。
最近更新 更多