我有一个全局单例,我的程序中的许多对象都使用它。当程序关闭时,这会导致崩溃 - 在单例本身被程序结束破坏之后,它会在某些对象的析构函数中使用。是否有一种可移植的方法来判断指针是否已在其上调用“删除”?在我的例子中,看起来删除会将指针的值更改为(void *)( - 1),但我不知道这是否是可移植的。
答案 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"
,我们很好)。现在,所有全局对象都在单个转换单元中定义,并以正确的顺序构造:用过的对象先于其用户构造,然后在其用户之后销毁。