11

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

我的问题是:

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

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

主.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但是当我使用or -O1or ...启用优化时-O2,输出只是一个新行:

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

G++ 版本:

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

2 回答 2

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

右边的默认初始化器,顾名思义,仅在您未在构造函数的初始化器列表中提供显式初始化器时使用。让我们看看你的:

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

好的,我们将委托给另一个构造函数。其他构造函数将执行完全初始化,因此不使用默认初始化程序。但是...我们传入somethingas 参数的未初始化值。

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

哦哦。现在我们尝试使用 的值_something,它是 的副本something,它是不确定的。未定义的行为和火灾随之而来。

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


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

Test(const int& number) : Test("SOMETHING HERE!!!", number) { }

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

static constexpr char *const defaultSomething = "SOMETHING HERE!!!";
Test(const int& number) : Test(defaultSomething, number) { }
于 2017-12-24T17:21:51.083 回答
15

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

哦,是你的错。默认成员初始化器仅用于在非委托构造函数中初始化成员对象。根据[class.base.init]/9,强调我的:

在非委托构造函数中,如果给定的潜在构造子对象不是由 mem-initializer-id 指定的(包括由于构造函数没有 ctor-initializer 而没有 mem-initializer-list 的情况),则

  • 如果实体是具有默认成员初始化程序的非静态数据成员,并且 [...] 实体是从 [dcl.init] 中指定的默认成员初始化程序初始化的;

所以something当你将它传递给目标构造函数时没有初始化。你的程序有未定义的行为,并且失败了。

于 2017-12-24T17:22:07.577 回答