C++初始化列表 - 我不明白

发布于 2024-10-19 11:08:27 字数 115 浏览 8 评论 0原文

在Effective C++中,初始化列表中的数据元素需要按照其声明的顺序列出。进一步说,这样做的原因是数据元素的析构函数以其构造函数的相反顺序被调用。

但我只是不明白这怎么会成为一个问题......

In Effective C++, it is said that data elements in the initialization list need to be listed in the order of their declaration. It is further said that the reasoning for this is that destructors for data elements get called in the reverse order of their constructors.

But I just don't see how this could be a problem...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

我早已燃尽 2024-10-26 11:08:27

我们考虑以下几点:

class Class {
    Class( int var ) : var1( var ), var2(var1 ) {} // allright
    //Class( int var ) : var2( var ), var1(var2 ) {} // var1 will be left uninitialized

    int var1;
    int var2;
};

第二个(注释掉的)构造函数看起来没问题,但实际上只有 var2 会被初始化 - var1 将首先被初始化,并且它将用 < code>var2 此时尚未初始化。

如果您以与类声明中列出的成员变量相同的顺序列出初始化程序,则此类错误的风险会大大降低。

Well consider the following:

class Class {
    Class( int var ) : var1( var ), var2(var1 ) {} // allright
    //Class( int var ) : var2( var ), var1(var2 ) {} // var1 will be left uninitialized

    int var1;
    int var2;
};

The second (commented out) constructor looks allright, but in fact only var2 will be initialized - var1 will be initialized first and it will be initialized with var2 that is not yet initialized at that point.

If you list initializers in the same order as member variables are listed in the class declaration risk of such errors becomes much lower.

尹雨沫 2024-10-26 11:08:27

当成员也是某种以某种方式相互依赖的类的对象时,构造和销毁的顺序可能很重要。

考虑一个简单的例子:

class MyString {
public:
  size_t s_length;
  std::string s;
  MyString(const char *str) : s(str), s_length(s.length()) {}
};

这个例子的目的是成员s_length保存存储字符串的长度。但这是行不通的,因为s_length将在s之前初始化。所以你在执行s的构造函数之前调用s.length

The order of construction and destruction may be important when the members are also objects of some class that somehow depend on each other.

Consider a simple example:

class MyString {
public:
  size_t s_length;
  std::string s;
  MyString(const char *str) : s(str), s_length(s.length()) {}
};

The intention in this example is that member s_length holds the length of the stored string. This will not work however, because s_length will be initialised before s. So you call s.length before the constructor of s is executed!

画▽骨i 2024-10-26 11:08:27

例如,如果您有一个这样的类:

class X {
  int a,b;
  X(int i) : b(i),a(b) { } // Constructor
};

类 X 的构造函数看起来像是首先初始化“b”,但实际上它是按照声明的顺序初始化的。这意味着它将首先初始化“a”。然而,“a”被初始化为“b”的值,而“b”尚未初始化,因此“a”将得到一个垃圾值。

For example if you have a class like this:

class X {
  int a,b;
  X(int i) : b(i),a(b) { } // Constructor
};

The constructor for class X looks like it initialises "b" first but it actually initialises in order of declaration. That means it will initialise "a" first. However "a" is initialised to the value of "b" which hasn't been initialised yet, so "a" will get a junk value.

小糖芽 2024-10-26 11:08:27

破坏是构造的逆过程,因此元素以相反的顺序被破坏。

假设我们有 2 个成员,abb 依赖于 a,但 a 不依赖于 b

当我们构造时,我们首先构造a,现在它存在,我们可以构造b。当我们解构时,如果我们首先解构a,这将是一个问题,因为b依赖于它。但我们首先破坏 b 并确保完整性。

这是典型的。例如,在群论中,fg 的逆是 ~g~f (其中 ~ff 的逆) code>)

穿衣服时,先穿袜子,再穿鞋。脱衣服时,先脱鞋,然后脱袜子。

Destruction is the reverse of construction, therefore elements are destructed in reverse order.

Let us say we have 2 members, a and b. b depends on a but a does not depend on b.

When we construct, we first construct a and now it exists we can construct b. When we destruct, if we destruct a first this will be a problem as b depends on it. But we destruct b first and integrity is ensured.

This is typical. For example in group theory, the inverse of fg is ~g~f (where ~f is the inverse of f)

When you dress, you first put on socks and then you put on shoes. When you undress you first remove the shoes, then the socks.

你穿错了嫁妆 2024-10-26 11:08:27

如果您的成员的构造函数之一抛出异常,也可能会出现问题。然后,所有已经正确构造的成员都必须按某种顺序进行析构,因为没有类似于析构函数的初始值设定项列表的东西。此顺序与类声明中成员的出现顺序相反。一个例子:

#include <iostream>

struct A1 {
  A1(int) { std::cout << "A1::A1(int)" << std::endl; }
  ~A1() { std::cout << "A1::~A1()" << std::endl; }
};

struct A2 {
  A2(int) { std::cout << "A2::A2(int)" << std::endl; }
  ~A2() { std::cout << "A2::~A2()" << std::endl; }
};

struct B {
  B(int) { std::cout << "B::B(int)" << std::endl; throw 1; }
  ~B() { std::cout << "B::~B()" << std::endl; }
};

struct C {
  C() : a1(1), a2(2), b(3) { std::cout << "C::C()" << std::endl; } // throw 1; }
  ~C() { std::cout << "C::~C()" << std::endl; }
  A1 a1;
  A2 a2;
  B b;
};

int main() {
  try {
    C c;
  } catch (int i) {
    std::cout << "Exception!\n";
  }
}

输出将是这样的:

A1::A1(int)
A2::A2(int)
B::B(int)
A2::~A2()
A1::~A1()
Exception!

It also could be a problem if one of the constructors of your members throws an exception. Then all members which were already properly constructed must be destructed in some order because there isn't something similar to initializer-lists for destructors. This order is the reverse order of appearance of the members in the class declaration. An example:

#include <iostream>

struct A1 {
  A1(int) { std::cout << "A1::A1(int)" << std::endl; }
  ~A1() { std::cout << "A1::~A1()" << std::endl; }
};

struct A2 {
  A2(int) { std::cout << "A2::A2(int)" << std::endl; }
  ~A2() { std::cout << "A2::~A2()" << std::endl; }
};

struct B {
  B(int) { std::cout << "B::B(int)" << std::endl; throw 1; }
  ~B() { std::cout << "B::~B()" << std::endl; }
};

struct C {
  C() : a1(1), a2(2), b(3) { std::cout << "C::C()" << std::endl; } // throw 1; }
  ~C() { std::cout << "C::~C()" << std::endl; }
  A1 a1;
  A2 a2;
  B b;
};

int main() {
  try {
    C c;
  } catch (int i) {
    std::cout << "Exception!\n";
  }
}

The output will be something like this:

A1::A1(int)
A2::A2(int)
B::B(int)
A2::~A2()
A1::~A1()
Exception!
抹茶夏天i‖ 2024-10-26 11:08:27

进一步说,推理
因为这是数据的析构函数
元素被反向调用
它们的构造函数的顺序。

请参阅 Steve Jessop 的评论 类组件初始化顺序

It is further said that the reasoning
for this is that destructors for data
elements get called in the reverse
order of their constructors.

See Steve Jessop's comment at Class component order of initialisation

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文