C++ 静态成员在仍有未完成的实例时被销毁?

C++ 静态成员在仍有未完成的实例时被销毁?,c++,segmentation-fault,destructor,static-members,C++,Segmentation Fault,Destructor,Static Members,我需要从析构函数访问静态数据成员,但在程序退出时,似乎无法保证它仍然存在!由于某些原因,静态成员正在被销毁,同时仍然存在该类的未完成实例。这很奇怪,因为我以前从未听过“从不从析构函数访问静态成员”的建议,但我认为如果存在这样的限制,我会知道的 我将给出一个具体的例子: class MyClass { public: ~MyClass() { m_instances.erase(m_name); } private: long m_name;

我需要从析构函数访问静态数据成员,但在程序退出时,似乎无法保证它仍然存在!由于某些原因,静态成员正在被销毁,同时仍然存在该类的未完成实例。这很奇怪,因为我以前从未听过“从不从析构函数访问静态成员”的建议,但我认为如果存在这样的限制,我会知道的

我将给出一个具体的例子:

class MyClass {
    public:
        ~MyClass() { m_instances.erase(m_name); }

    private:
        long m_name;
        static std::map<long, MyClass*> m_instances;
};
class-MyClass{
公众:
~MyClass(){m_实例。擦除(m_名称);}
私人:
长m_名称;
静态std::映射m_实例;
};
在另一节课上,我尝试了下面这个看起来很有效的讨厌的方法,但是当我想到它的时候,我觉得它根本不是一个解决方案

class MyClass {
    friend class Switch;

    public:
        ~MyClass() { if (m_alive) m_instances.erase(m_name); }

    private:

        static bool m_alive;
        class Switch {
            ~Switch() { MyClass::m_alive = false; }
        };
        static Switch m_switch;

        long m_name;
        static std::map<long, MyClass*> m_instances;
};
class-MyClass{
朋友级交换机;
公众:
~MyClass(){if(m_alive)m_实例。擦除(m_名称);}
私人:
静态bool m_活着;
类开关{
~Switch(){MyClass::m_alive=false;}
};
静态开关m_开关;
长m_名称;
静态std::映射m_实例;
};
如果MyClass的一个实例在m_实例之后但在m_切换之前被销毁怎么办??即使m_开关先死掉,布尔m_alive也可能被“销毁”,因此可能被覆盖为“true”(我知道这不太可能)


那么谁能提供更好的解决方案呢?我想我在这里遗漏了一些非常明显的东西。

如果你在一个静态类中遇到这些问题,那一定意味着MyClass也有静态作用域,你不能在一个静态访问另一个静态的情况下设计这样的代码。它可能会起作用,也可能不会起作用,因为你对破坏顺序有问题


也完全有可能是另一个全局(静态)导致内存损坏。如果是这种情况,则可能意味着覆盖一个全局可能会覆盖位于同一内存空间中的另一个相邻全局,即您遇到问题的静态已损坏且未被删除。

不能保证只有在同一类的对象的所有实例之后才会销毁静态成员。C++没有引用计数范例(<代码> SyddYPPTR < /代码>)。

在考虑生存期时,将静态成员视为任何其他静态对象。除了位于类的“名称空间”(警告:术语不准确)之外,实际上没有任何东西将它们绑定到它们的包含类

这样,如果您的代码> MyCys< /Cord>实例也是静态创建的,那么您需要考虑它们之间的正常静态对象生存期规则:

:


这里的情况正好相反。对于您当前的问题,这是一个廉价的修复程序,但我的建议是完全避免静态实例;你只会陷入更多类似这样的静态初始化陷阱。。。可能与未来的化身相同的代码

这显然是一个静态破坏顺序的问题。我想推荐如下内容:

class MyClass {
    public:
        MyClass() { add_instance(m_name, this); };
        ~MyClass() { erase_instance(m_name); }

    private:
        long m_name;
        static std::map<long, MyClass*>& get_instance_map();
        static void add_instance(long aName, MyClass* aObj);
        static void erase_instance(long aName);
};

std::map<long, MyClass*>* MyClass::get_instance_map() {
  static std::map<long, MyClass*>* p_inst = new std::map<long, MyClass*>();
  return p_inst;
};

void MyClass::add_instance(long aName, MyClass* aObj) {
  static std::map<long, MyClass*>* p_inst = MyClass::get_instance_map();
  p_inst->insert( std::make_pair(aName, aObj) );
};

void MyClass::erase_instance(long aName) {
  static std::map<long, MyClass*>* p_inst = MyClass::get_instance_map();
  p_inst->erase( aName );
};
class-MyClass{
公众:
MyClass(){add_instance(m_name,this);};
~MyClass(){erase_实例(m_名称);}
私人:
长m_名称;
静态std::map&get_instance_map();
静态void add_实例(long aName,MyClass*aObj);
静态无效擦除_实例(长aName);
};
std::map*MyClass::get_instance_map(){
静态std::map*p_inst=new std::map();
返回p_inst;
};
void MyClass::add_实例(long aName,MyClass*aObj){
静态std::map*p_inst=MyClass::get_instance_map();
p_inst->insert(标准::生成对(aName,aObj));
};
void MyClass::erase_实例(长名称){
静态std::map*p_inst=MyClass::get_instance_map();
p_inst->擦除(aName);
};

如果需要删除实例映射,则可能无法删除。否则,只需在第一次使用习惯用法时使用正常的构造。这里的要点是,映射是一个由堆分配的std::map对象,不删除它只意味着当操作系统回收freestore内存时,它将被清除,这将在每隔一次“正常”执行(如析构函数调用)后发生。

对我来说似乎很奇怪。你在哪个编译器/平台上遇到过这种情况?是什么东西在程序出口处抓住了
MyClass
的实例,从而使它们的析构函数运行?我想知道这是否是一种类似的情况:你在说什么
m_开关
?上面的代码中没有
m_开关
。您当然可以从析构函数访问全局和静态变量。这只会发生在全局对象上,并且只会在程序结束时发生。将一个对象封装为另一个命名空间中的静态对象不会改变它基本上是全局对象的事实object@drhirsch例如我刚才说了这么多!(你使用“全局”是不对的。)是的:-)但我认为这不相关,因为我无法想象OP会使用全局MyClass,可能会在全局MyClass之后创建一个静态成员,然后问他为什么在访问静态成员时遇到问题。。。现在我不再那么肯定了;-)@赫希博士:我的答案是基于一个有根据的猜测,那就是问题的原因。:)毕竟,如果不是这样,那么这种情况就不应该发生。@Mikael:如果只构建了一个MyClass,然后立即销毁,然后又构建了另一个MyClass,会发生什么?你的地图丢了吗?哦,是的,真的!我怎么会错过呢。我将修复一个编辑。@Mikael:我认为您在函数习惯用法中使用了静态指针,但这被认为是故意“泄漏”它创建的实例。这似乎很好。非常感谢。有没有正式的方式将这个问题标记为“已解决”?@Rob:点击选票下方的大勾号,选择你喜欢的答案。
#include <iostream>

struct A {
    A() { std::cout << "*A "; };
   ~A() { std::cout << "~A "; };
};

struct B {
    B() { std::cout << "*B "; };
   ~B() { std::cout << "~B "; };

    static A a;
};

A B::a;
B t;

int main() {}

// Output: *A *B ~B ~A 
class MyClass {
    public:
        MyClass() { add_instance(m_name, this); };
        ~MyClass() { erase_instance(m_name); }

    private:
        long m_name;
        static std::map<long, MyClass*>& get_instance_map();
        static void add_instance(long aName, MyClass* aObj);
        static void erase_instance(long aName);
};

std::map<long, MyClass*>* MyClass::get_instance_map() {
  static std::map<long, MyClass*>* p_inst = new std::map<long, MyClass*>();
  return p_inst;
};

void MyClass::add_instance(long aName, MyClass* aObj) {
  static std::map<long, MyClass*>* p_inst = MyClass::get_instance_map();
  p_inst->insert( std::make_pair(aName, aObj) );
};

void MyClass::erase_instance(long aName) {
  static std::map<long, MyClass*>* p_inst = MyClass::get_instance_map();
  p_inst->erase( aName );
};