委托构造函数在使用类字段进行参数时会出现分段错误

时间:2017-12-24 17:12:51

标签: c++ native raspberry-pi3 delegating-constructor

实际上,分段错误发生在我试图编译的另一个程序中,这是因为这种行为。

我的问题是:

  

这是一个错误还是我的错?

以任何方式重现(即使something字段是私有的或受保护的),这是我的例子:

main.cc:

#include <iostream>
class Test {
    public:
        const char* something = "SOMETHING HERE!!!";
        Test(const int& number) : Test(something, number) { }
        // XXX: changed `something` to `_something` to make it different
        Test(const char* _something, const int& number) {
            std::cout << _something << std::endl;
            std::cout << number << std::endl; }
        ~Test() { }
};

int main(int argc, char* argv[]) {
    Test te1(345);
    Test te2("asdasdad", 34523);
    return 0;
}

以下是编译时会发生的事情:

g++ main.cc -Os -o main

并以:

运行
./main

输出是:

pi@pi:~/ $ ./main
A"�~ <-- this is random
345
asdasdad
34523

但是当我使用-O0-O1-O2启用优化时......输出只是一个新行:

pi@pi:~/ $ ./main
pi@pi:~/ $

G ++版:

pi@pi:~/ $ g++ --version
g++ (Raspbian 6.3.0-18+rpi1) 6.3.0 20170516

2 个答案:

答案 0 :(得分:20)

const char* something = "SOMETHING HERE!!!";

正如其名称所示,右侧的默认初始化程序仅在您未在构造函数的初始化程序列表中提供显式初始值设定项时使用。让我们看看你的:

Test(const int& number) : Test(something, number) { }

好的,我们将委托给另一个构造函数。其他构造函数将执行完全初始化,因此不使用默认初始值设定项。但是......我们将something的未初始化值作为参数传递。

Test(const char* _something, const int& number) { /* ... */ }

糟糕,现在我们正在尝试使用_something的值,somethingTest(const int& number) : Test("SOMETHING HERE!!!", number) { } 的副本,这是不确定的。未定义的行为和火灾随之而来。

你真的不应该将类成员的值作为参数传递给它的构造函数,除非你有无限量的防火鸡和鸡蛋。

您可以通过将默认值放在对委托构造函数的调用中来获取您要查找的行为:

static constexpr char *const defaultSomething = "SOMETHING HERE!!!";
Test(const int& number) : Test(defaultSomething, number) { }

...或将其保存在专用的静态变量中:

something

答案 1 :(得分:15)

  

这是一个错误还是我的错?

哦,这是你的错。默认成员初始值设定项仅用于在非委派构造函数中初始化成员对象。根据{{​​3}},强调我的:

  

在非委托构造函数中,如果给定的可能构造的子对象未由mem-initializer-id指定   (包括没有mem-initializer-list的情况,因为   构造函数没有ctor-initializer),然后

     
      
  • 如果实体是具有默认成员初始值设定项的非静态数据成员,则该实体从其初始化   [dcl.init];
  • 中指定的默认成员初始值设定项   

因此,当您将.footer > :only-child { margin-left: auto; margin-right: auto; } 传递给目标构造函数时,它不会被初始化。你的程序有不明确的行为,并且破产了。