你能判断一下C ++指针是否被破坏了吗?

时间:2011-09-19 23:26:04

标签: c++

我有一个全局单例,我的程序中的许多对象都使用它。当程序关闭时,这会导致崩溃 - 在单例本身被程序结束破坏之后,它会在某些对象的析构函数中使用。是否有一种可移植的方法来判断指针是否已在其上调用“删除”?在我的例子中,看起来删除会将指针的值更改为(void *)( - 1),但我不知道这是否是可移植的。

8 个答案:

答案 0 :(得分:6)

不,无法判断C ++指针指向的对象是否已被破坏。

您可以使用自动处理它的智能指针。

答案 1 :(得分:1)

简单回答:

  • 不要使用指针。
  • 使用经典的迈尔斯单身人士。

然后保证在对象确保在对象之前实例化之后它被销毁。要确保在对象刚才在对象的构造函数中使用它之前实例化它。

经验法则:如果要在析构函数中使用单例。首先在构造函数中使用它。

class A
{
    A();
    A(A const&);
    A& operator=(A const&);
    public:
        static A& getInstance()  // return reference.
        {
            static A instance;  // Created on first use.
                                // So lazily created when expensive.

            return instance;    // Guaranteed to be destroyed in reverse order of
                                // creation In comparison to other static storage
                                // duration objects. Thus if it is created before
                                // your object It is guaranteed to be correctly
                                // destroyed after your object.

                                // If you want to guarantee it is created before your
                                // object just call A::getInstance() in your constructor
                                // the static member 'instance' will only be created
                                // once and returning a reference is not expensive.
        }
        // If you are creating this from the constructor of a global
        // Then threading becomes a non issues as threads are not started before main
        // If you are using pthreads or Windows threads you potentially can start them
        // but it is undefined if they will work so again not your issue.
};

答案 2 :(得分:0)

不可能,我认为这也是一个未定义的区域。

你最好的选择是在清除其他所有内容之前不删除你的单例,否则在删除实例后将指针设置为NULL然后你可以检查它。听起来我觉得有些重构是有道理的。

答案 3 :(得分:0)

如前所述,不,你不能。有不同的技术可以跟踪它,但它们与平台有关。

首先,您案件中的实际问题是什么?你有一个单例,当它们被销毁时被其他对象使用。如果您的单身人士被C Runtime摧毁,那么会破坏其他对象吗?

答案 4 :(得分:0)

确定删除单例的简单方法是简单地使单例的析构函数变为私有。然后,您应该在尝试删除它的任何地方收到编译错误。

答案 5 :(得分:0)

此代码将跟踪静态实例的生命周期;如果堆分配,则同样有效。 当然,即使实例尚未构建,它也将首次调用instance()。 但是,如果您有一些全局静态析构函数的复杂网格,您应该能够使用它来确定实例是否已被破坏。

class Thing
{
public:
    enum State { preConstruction, constructed, destructed };
    static const State& singletonState() { return state_;}
    static Thing& instance()
    {
        static Thing instance;
        return instance;
    }
private:
    Thing()
    {
        state_ = constructed;
    }
    ~Thing()
    {
        state_ = destructed;
    }
    static State state_;
};

Thing::State Thing::state_ = Thing::preConstruction;

答案 6 :(得分:0)

另一种选择是在调用delete之后,将指针设置为NULL。然后,您可以检查指针是否为NULL,并知道该指针已被删除(或尚未初始化)。

class MyClass
{
  public:
    MyClass()
    {
      pPointer = new NewClass();
    }

    ~MyClass()
    {
      delete pPointer;
      pPointer = NULL;
    }

  private:
     NewClass *pPointer;
}

答案 7 :(得分:0)

如果对象是在单独的文件中定义的,则C ++不会定义两个全局构造函数或析构函数的调用顺序。但是,如果对象是在同一文件中定义的,则有一个顺序:文件作用域对象是按词法顺序(它们在文件中出现的顺序)构造的,并以相反的顺序销毁。

可以将其与头文件依赖项结合使用,以将命令引入C ++全局构造和销毁,如下所示:

// header file A.h
#ifndef A_H_INCLUDED
#define A_H_INCLUDED
class A { /* ... */ };

#ifdef DEFINE_GLOBALS
A a_singleton;
#endif
#endif

// header file B.h
#ifndef B_H_INCLUDED
#define B_H_INCLUDED
#include "A.h"
class B : { A *pa_memb; /* ... */ }

#ifdef DEFINE_GLOBALS
B b_singleton;
#endif
#endif

// header file C.h
#ifndef C_H_INCLUDED
#define C_H_INCLUDED
#include "B.h"
#include "A.h"
class C : { A *pa_memb, B *pb_memb; /* ... */ }

#ifdef DEFINE_GLOBALS
C c_singleton;
#endif
#endif

然后,我们有一个名为globals.cc的文件在这里:

// globals.cc
#define DEFINE_GLOBALS
#include "C.h"
#include "A.h"
#include "B.h"

标头中的#include防护将确保global.cc中的包含物具有正确的依赖关系顺序(并且可能会拾取丢失的包含物:在上面的示例中,如果我们仅包含"C.h",我们很好)。现在,所有全局对象都在单个转换单元中定义,并以正确的顺序构造:用过的对象先于其用户构造,然后在其用户之后销毁。