成员初始化列表。参数求值顺序

3
一个包含成员初始化列表的代码示例。
#include <memory>

struct Throwable
{
    Throwable()
    {
        throw "Exception!";
    }
};

struct A
{
    A() : t(Throwable()), i(new int()) {}

    Throwable t;
    std::unique_ptr<int> i;
};

如果按照以下评估顺序,我是否可能有内存泄漏?

  1. new int()
  2. Throwable()
  3. t()
  4. i()

标准中的顺序是什么?我们有一些规则。

https://en.cppreference.com/w/cpp/language/initializer_list

3)接下来,非静态数据成员按照在类定义中的声明顺序进行初始化。
因此,t将在i之前构造。

https://en.cppreference.com/w/cpp/language/eval_order

9) 内置逗号运算符的第一个(左)参数的每个值计算和副作用都在第二个(右)参数的每个值计算和副作用之前被排序。

但成员初始化列表由于先前的引用而不使用所有逗号规则。而且它不是逗号运算符(https://en.cppreference.com/w/cpp/language/operator_other#Built-in_comma_operator)。

10) 在列表初始化中,给定初始化程序子句的每个值计算和副作用都在大括号包围的逗号分隔的初始化器列表中跟随它的任何初始化程序子句的每个值计算和副作用之前被排序。

并且 https://en.cppreference.com/w/cpp/language/list_initialization

在以下情况下执行列表初始化:

5) 如果使用了大括号初始化列表,则在构造函数的成员初始化列表中

我还有另一个情况。

你能提供定义成员初始化列表中参数求值顺序的规则吗?


声明的顺序? - Vivick
评估顺序。我需要用“sequenced-before”(https://en.cppreference.com/w/cpp/language/eval_order)的术语来回答。 - Iurii Popov
"Standard 中的顺序是什么?" - 我 讨厌 这种问题。为什么你不自己在标准中查找答案呢? - Jesper Juhl
2
@JesperJuhl:因为标准很拗口,这话是从一个实际上成功理解了C++对象模型的人嘴里说出来的。例如,我本来期望在[class.base.init]中找到成员初始化列表的定义并在其中找到这个问题的答案,但是它并不在那里。事实上,它在10章之前的[intro.execution]中。为什么?因为它恰好被一般性语句所涵盖而不是特定的语句。标准中的信息通常分散得足够广泛,以至于对其提出问题是不无道理的。 - Nicol Bolas
2
@JesperJuhl 标准文档并不一定简单明了。我知道我花了很长时间才有信心理解标准文档。即使过了多年,有时我仍然很难确定我的解释是否正确。从他的问题中可以看出,他确实努力寻找答案。虽然“RTFM”可能是对许多问题的有效回答,但我认为“在标准文档中查找”不是对一个合法的C++问题的有用回答,特别是一个明确询问标准规定的问题... - Michael Kenzel
显示剩余3条评论
2个回答

4
不,这种可能导致信息泄露的评估顺序是有保证不会发生的。每个 mem-initializer 中的表达式都是一个 full-expression ( [intro.execution]§5.3 )。而[intro.execution] §9告诉我们:

与每个完整表达式相关的每个值计算和副作用都在要评估的下一个完整表达式相关的每个值计算和副作用之前排序。

换句话说,在初始化成员使用的每个表达式的评估完成之前,将完成下一个成员的表达式的评估。

0
如果按照以下顺序进行评估,我会有内存泄漏吗?
答案是否定的,因为非静态成员的初始化顺序与类定义中成员声明的顺序相同,而不是与成员初始化列表中的顺序相关。这是因为销毁需要按照构造的相反顺序执行,为了实现这一点,在销毁开始时必须遵循规则。关于这一点,由于您在任何其他成员之前声明了可抛出类型的成员,它将首先被构造并在堆分配发生之前抛出。没有泄漏。
但是,如果您在unique_pointer声明之后声明了可抛出类型的成员,则在初始化过程中将首先进行堆分配,然后从可抛出类型的构造函数中抛出异常,将停止A的构造,即使捕获了异常,在异常处理程序执行后也会重新抛出异常,但是遵循任何已构造的类成员也将被销毁的规则,unique_pointer的资源管理能力也将防止泄漏。在这种情况下,我希望这个小观察可以帮助到您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接