2013-11-26 69 views
0

我看,这是很好的做法,这样做在类的析构函数检查缺失的指针数据成员依次如下:C++中NULL指针和const正确性

if(0 != m_pPointer) 
{ 
    delete m_pPointer; 
    m_pPointer= 0; 
} 

然而,我发现,这可以防止你

Type* const m_pPointer; 

是不是分配到NULL指针(如在我的上面的例子)对于常量-正确性的屏障:如下声明const的指针作为数据成员? 什么是最好的办法?保持一切const并停止将NULL分配给删除的指针或声明non-const指针,即使它们的地址永不改变?

+6

我不同意这是一个很好的做法。双删除指针几乎总是应用程序中的逻辑错误,并且在删除后将指针设置为空可隐藏该错误。如果您没有将其设置为空,则该应用可能会崩溃,这是件好事。 – JohannesD

+1

你有没有使用情况下,将指针设置为0实际上有助于任何事情?我以前见过这种模式,但除非您将引用导出为指针,否则我无法看到它。 – juanchopanza

+0

@JohannesD但是'双删除'在哪里呢?将NULL指向指针不会释放内存。 '如果你没有将它设置为null,那么应用程序可能会崩溃,这是一件好事情 - 将它设置为null也会崩溃脚趾应用程序,不是吗? –

回答

6

这是由于以下原因,不好的做法:

  1. 在析构函数的指针设置为null会掩盖加倍的毁坏问题。良好的做法是尽早发现问题。
  2. delete之前检查空指针是否仅添加不必要的代码。 delete通过无所事事处理空指针。良好的做法是尽量减少代码量。
+0

同意。 'if'支票被浪费了,是一种不必要的负担。 –

+0

那么是或不是可以有像'delete m_pPointer; m_pPointer = 0;'在我们的代码中?将NULL分配给指针可以保证如果稍后在该指针上调用了某个内容,程序将会崩溃。这不是一件好事吗? –

+2

@JasonSwartz你打算展示一个例子,以后可以怎样调用这个指针?如果你设法做到这一点,你会发现它很有人气,而且设计很差。无论如何,你只是将问题转移到其他地方。 – juanchopanza

1

删除空指针是有保证的安全的,所以空检查是毫无意义的。

如果一个类的成员是一个指向非const对象的const指针,那么你说的指针值在包装对象的生命周期内不会改变 - 这种情况下,你应该只做这个指向的对象将比包装对象长或长,并且包装对象永远不会指向不同的对象。

事实上,你有这个问题只是意味着你在错误的地方使用了一个const指针。你声称,在你的情况下,指针值永远不会改变,但在你的例子中,它显然会做 - 它变为null。

+0

问题的关键在于值*是否应该变为null。答案是,不,它不应该,而且应该是常量。 – JohannesD

+0

也许,在您的真实世界的情况下,不能从片段派生。也就是说,当一个成员指针在包装器对象的生命周期中被多次删除和重新分配时,它*可以成为公平的策略来始终确保指针指向一个对象或为空,然后重新创建该对象可以简单地'删除“,然后”新建“。如果指向的对象在初始化列表中实例化并在析构函数中销毁,那么不需要将其设置为null,并且它可以是一个const指针 - 或者甚至可以将它放在堆栈上。 –

1

当您将静态库与来自两个不同共享库(在Linux上)的全局或静态对象链接到相同的可执行文件时,可能会导致一个奇怪的情况。每个共享的lib对象都向构造函数和析构函数插入调用,因此您将有一个对象和两个对同一对象的构造函数和析构函数的调用(实际上您将有2个对象映射到相同的地址)。

当你的应用在第二析构函数中崩溃时,你可能会发现问题。 如果你是NULL,你永远不会知道有问题。

你的问题:由于上述以外的问题,我想你应该截然不同的两种类型的指针: 请参见下面的类:

class A{ 
    obj *x, *y; 
    A(){ 
    x = new obj; 
    y = NULL 
    } 
    ~A(){ 
    delete x; 
    if(y)delete y; // the `if` here will save the calling and returning run time when NULL. 
    } 
    void RecicleX(){ 
    delete x; 
    x = new obj; 
    } 
    void InitY(){ 
    assert(y==NULL); //illegal to call init when already 
    y = new obj; 
    } 
    void TermY(){ 
    assert(y); //illegal to call term when already inited 
    delete y; 
    y = NULL; //prevent crush in dtor if called after... 
    } 
}; 

X始终存在,所以没有需要检查它,无需将其清空。你可能存在也可能不存在,所以我认为你应该在删除后清空它。 (你也许会想也知道目前的状态,像assert

1

“做最好的方法” 是:

class foo { 
    std::unique_ptr<bar> m_pPointer; 
public: 
    foo(std::unique_ptr<bar> pPointer) 
    : m_pPointer{std::move(pPointer)} {} 
}; 

或常量,

class foo { 
    const std::unique_ptr<bar> m_pPointer; 
public: 
    foo(std::unique_ptr<bar> pPointer) 
    : m_pPointer{std::move(pPointer)} {} 
}; 

没有new ,没有delete,没有析构函数。