编译器未捕获未初始化的成员。它是一个错误吗?

Posted

技术标签:

【中文标题】编译器未捕获未初始化的成员。它是一个错误吗?【英文标题】:Uninitialized member not caught by compiler. Is it a bug? 【发布时间】:2021-06-28 09:25:00 【问题描述】:

作为一个糟糕的c++程序员,我今天遇到了这个segfault:一个未初始化的shared_ptr 给了一个NULL,我的程序崩溃了。对于普通班级成员,如果成员未初始化,我会收到警告或错误。但在这种情况下不是。我在下面制作了一个复制品。

在调试模式下,此段错误。我没有收到预期的未初始化变量的编译器错误或警告。

这是一个错误吗?还是我误会了。 编译器不应该在这段代码上发出警告或错误吗?

我根本不希望它编译!

我认为编译器应该报错,说你需要在类构造函数中初始化私有wooo...

#include <iostream>
#include <memory>
#include <vector>
using namespace std;

class Wooo
public:
    int maybe;
    int istrue()
        return maybe + 1;
private:
    Wooo(); // just to be explicit about deleted default constructor
;

class Weee
public:
    Weee(); // just empty constructor. reading wooo anywhere will give a NULL
    
    Wooo seg_me()
        return *wooo.get();
    ;
private:
    const std::shared_ptr<Wooo> wooo;
;

int main()
   
    auto w = Weee();
    cout<<"Hello World\n";
    cout<< w.seg_me().istrue() << "\n";

    return 0;



【问题讨论】:

嗯,它初始化...到nullptr。恐怕您的编译器不够聪明,无法警告您取消引用该空指针,但也许另一个静态分析器会。 识别 Undefined Behavior 的实例或其他有问题的代码属于 实施质量,因为这样做的范围从微不足道到不可能甚至如果你能解决停机问题。编译器通常只是假设它不会发生,并积极修剪路径以弥补不完美的信息并实现高效的代码。在运行时留下陷阱进行识别通常会降低效率,因此沦为调试模式和低优化。 可以确认,此行为被未定义的行为清理程序捕获。使用 -fsanitize=undefined 构建就像圣诞树一样点亮它 【参考方案1】:

一个未初始化的 shared_ptr ...

我认为编译器应该报错并说你需要初始化私有的wooo

没有未初始化。它只是默认初始化的。通过其默认构造函数。致nullptr

未显式初始化的shared_ptr 等价于原始指针

Wooo *wooo = nullptr;

这是一个错误吗?

是的,这是您的代码中的一个错误:您允许指针被默认初始化,然后在实际指向某个地方之前取消引用它。


你有两种可能的情况:

    绝不允许Weee::wooo 包含nullptr

    在这种情况下,错误是您编写的构造函数未能建立您的类不变量。

    你应该有

    Weee() : wooomake_shared ... 
    

    和/或

    explicit Weee(shared_ptr<Wooo>&& p) : wooostd::move(p) 
    

    或其他。

    关键是 如果 有一个非 nullptr 成员是一个类不变量,那么 任何 构造函数或方法可能会使这个不满足是错误的。

    有时允许Weee::wooo 包含nullptr,因为您有两阶段初始化 (boo),或者因为它实际上是可选的或有条件的。

    在这种情况下,错误是您在取消引用之前没有检查指针是否(非常合法)nullptr

【讨论】:

好的。这主要回答了我想知道的问题。我所期望的是编译器会看到我的错误(忘记编写正确的构造函数)如何用类型捕获这种情况? 如果这是所需的行为,您可以编写一个限制为非空的智能指针,例如GSL 中的not_null。但是您仍然需要首先确定预期的语义是什么,而您还没有解决这个问题。

以上是关于编译器未捕获未初始化的成员。它是一个错误吗?的主要内容,如果未能解决你的问题,请参考以下文章

C++17 编译器不应该发现对未定义值的传递引用吗?

查找未初始化成员变量的简单方法

Symfony 2,未定义的变量,在构造函数中初始化为 ArrayCollection 的受保护成员通过错误,它是未定义的

从源代码编译 MongooseIM 时 rebar_core 中未捕获的错误

编译器未将向量识别为类成员

错误 C2511 - 未找到重载的成员函数