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_o​​perator)。

10) 在列表初始化中,给定初始化器子句的每个值计算和副作用都排在与任何初始化器子句相关联的每个值计算和副作用之前,该初始化器子句在括号括起来的逗号分隔的初始化器列表中。

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

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

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

我还有一个案例。

您能否提供定义成员初始化器列表中参数评估顺序的规则?

4

2 回答 2

3

不,保证不会发生这种可能导致您泄漏的评估命令。每个mem-initializer中的表达式是一个完整的表达式[intro.execution] §5.3)。[intro.execution] §9告诉我们

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

因此,换句话说,用于初始化成员的每个表达式的计算在开始计算下一个成员的表达式之前完成。

于 2018-07-28T13:49:31.203 回答
0

如果可能有以下评估顺序,我会不会有内存泄漏?

答案是不,

因为非静态成员的初始化顺序被定义为与类定义中成员声明的顺序相同,与成员初始化列表中的顺序无关,因为销毁需要以构造的相反顺序执行,以实现, 破坏开始时必须遵守规则。关于这一点,由于您在任何其他成员之前声明了类型为 throwable 的成员,它将首先构造并在堆分配发生之前抛出。没有泄漏。

但是如果你在unique_pointer声明之后声明了throwable类型的成员,那么在初始化过程中会先进行堆分配,然后从throwable构造函数中抛出异常,将停止A构造,即使被捕获,异常也会在异常处理程序之后重新抛出执行,但遵循任何构造的类成员也将被破坏的规则,unique_pointer 的资源管理功能将防止泄漏,在这种情况下也是如此。

我希望这个小小的观察会有所帮助。

于 2018-07-29T00:52:57.867 回答