我写了一个非常小的 Observeable 实现。当观察者注册时,它会删除旧观察者并启动新观察者。但是,即使它尚未初始化,它也会尝试删除指针。代码如下:
Observable.h
class Observable
{
public:
Observable();
virtual void registerObserver(Observer * O);
virtual ~Observable();
protected:
Observer * myObserver;
};
Observable.cpp
#include "Observable.h"
Observable::Observable()
{
}
Observable::~Observable()
{
if(myObserver)
delete myObserver;
}
void Observable::registerObserver(Observer * O)
{
if(myObserver)
delete myObserver;
myObserver=O;
}
所有主要做的是
GUI * gui = new GUI(); // GUI extends Observer
Model * m = new Model(); //Model extends Observable
m->registerObserver(gui); //I get a segfault inside this call
如果我单步执行registerObserver
,我看到即使我从未初始化myObserver
,语句 if(myObserver)评估为 true 。这会导致未初始化的指针被删除并出现seg错误。
值得注意的是,如果我运行发布版本,我就不会遇到段错误。我只在调试版本中收到错误。
我认为 if(myObserver)只会在指针完好无损的情况下评估为 true 。 (即初始化但未删除)。
答案 0 :(得分:6)
其他人已经解释了为什么你因为未初始化的指针而得到分段错误,以及如何解决这个问题。您还有其他错误等待发生,因为您没有关注rule of three。如果您复制Observable
类,则两个实例现在都将包含myObserver
的副本,并且两者都将尝试在其各自的析构函数中delete
指针,从而导致未定义的行为,以及可能是崩溃。
更好的实现是遵循rule of zero而不是自己管理指针。
#include <memory>
class Observable
{
public:
Observable();
virtual void registerObserver( std::unique_ptr<Observer> O );
virtual ~Observable();
protected:
std::unique_ptr<Observer> myObserver;
};
Observable::Observable()
// no need to initialize pointer
{}
Observable::~Observable()
{
// no need to delete pointer manually
}
void Observable::registerObserver( std::unique_ptr<Observer> O )
{
myObserver.reset( O.release() );
}
答案 1 :(得分:4)
您没有在代码中初始化myObserver
,因此它的初始值不可知。您需要明确初始化它:
Observable::Observable() : myObserver(nullptr)
{
}
答案 2 :(得分:1)
没错。你从来没有初始化它,所以它的值是未定义。这意味着你不知道它可能包含什么值,因为没有设置任何值。当然不能保证是NULL。
你应该总是初始化你的指针。通常的方法是使用构造函数中的initialiser-list语法执行此操作:
Observable::Observable()
: myObserver(NULL)
{ }
答案 3 :(得分:1)
默认情况下不初始化C ++成员变量。这意味着您的myObserver
变量不能依赖于您的示例中的0
。
您需要在构造函数中添加一个初始化,以摆脱未定义行为。
答案 4 :(得分:0)
你需要
Observable::Observable() : myObserver(0)
{
}
仅当!mypointer
等于0(mypointer
,NULL
等)时, nullptr
才会评估为真,但在您明确设置之前,它只是未定义 - 有些随机值。