编译器未捕获未初始化的成员。它是一个错误吗?
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
。但是您仍然需要首先确定预期的语义是什么,而您还没有解决这个问题。以上是关于编译器未捕获未初始化的成员。它是一个错误吗?的主要内容,如果未能解决你的问题,请参考以下文章
Symfony 2,未定义的变量,在构造函数中初始化为 ArrayCollection 的受保护成员通过错误,它是未定义的