你能判断一个c++指针是否被销毁了吗?

Can you tell if a C++ pointer has been destructed?

本文关键字:是否 指针 c++ 判断 一个      更新时间:2023-10-16

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

不能,不能判断c++指针所指向的对象是否已被销毁。

你可以使用智能指针,它会自动处理。

简单回答:

  • 不要使用指针
  • 使用经典的Myers单例。

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

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

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.
};

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

你最好的办法是在其他所有东西都被清理干净之前不要删除你的单例,否则在删除实例后将指针设置为NULL,然后你可以检查它。在我看来,一些重构是有序的。

正如已经说过的,不,你不能。有不同的技术来跟踪这一点,但它们是依赖于平台的。

首先,你的实际问题是什么?你有一个单例,它被其他对象销毁时使用。如果你的单例被C运行时销毁了,那么是什么销毁了其他对象呢?

判断是什么在删除单例的简单方法是将单例的析构函数设为private。然后,您应该在试图删除它的任何地方得到编译错误。

这段代码将跟踪静态实例的生命周期;如果使用堆分配,效果同样好。当然,即使实例还没有构造,它也会在第一次调用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;

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

class MyClass
{
  public:
    MyClass()
    {
      pPointer = new NewClass();
    }
    ~MyClass()
    {
      delete pPointer;
      pPointer = NULL;
    }
  private:
     NewClass *pPointer;
}

如果对象定义在单独的文件中,则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",我们就很好)。现在,所有的全局对象都在一个翻译单元中定义,并按照正确的顺序构造:使用的对象在其用户之前构造,在其用户之后销毁。