静态成员在仍有未完成的实例的情况下被销毁?

发布于 2024-11-06 08:49:18 字数 969 浏览 6 评论 0原文

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

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

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

    private:
        long m_name;
        static std::map<long, MyClass*> m_instances;
};

在另一堂课上,我尝试了以下令人讨厌的黑客,它似乎有效,但当我想到它时,我认为这根本不是一个真正的解决方案。

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

如果 MyClass 的实例在 m_instances 之后但在 m_switch 之前被销毁怎么办?即使 m_switch 首先死亡,布尔值 m_alive 也可能已被“破坏”,因此可能被覆盖为“true”(我知道不太可能)。

那么有人可以提供更好的解决方案吗?我希望我在这里遗漏了一些非常明显的东西。

I need to access a static data member from a destructor, but on program exit it seems that it cannot be guaranteed to still exist! For some reason, the static members are being destroyed whilst there are still outstanding instances of the class. It's odd because I've never heard the advice "Never access static members from a destructor" before, and yet I think I'd know about such a limitation if it existed.

I'll give a concrete example:

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

    private:
        long m_name;
        static std::map<long, MyClass*> m_instances;
};

In another class, I tried the following nasty hack which appeared to work, though when I think about it I don't think it's really a solution at all.

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

What if an instance of MyClass is destroyed after m_instances but before m_switch?? And even if m_switch dies first, the boolean m_alive might have been "destroyed" and therefore possibly overwritten to 'true' (unlikely, I know).

So can anyone offer a better solution? I expect I am missing something very obvious here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眼前雾蒙蒙 2024-11-13 08:49:18

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

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

如果您需要删除实例映射,则可能无法实现。否则,只需使用正常的“首次使用构造”习惯用法即可。这里的要点是,map 是一个堆分配的 std::map 对象,不删除它仅仅意味着它会被刷新,因为操作系统回收 freestore 内存,这将在每隔一个“正常”执行之后发生,就像析构函数调用。

This is clearly a problem of static destruction order. I would recommend something like the following:

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

If you need the instance map to be deleted, it might not be possible. Otherwise, just use a normal construct-on-first-use idiom. The point here is that the map is a heap-allocated std::map object, and not deleting it just means that it will be flushed away as the OS reclaims the freestore memory which will occur after every other "normal" execution, like a destructor call.

烟─花易冷 2024-11-13 08:49:18

不能保证静态成员仅在同一类的对象的所有实例之后才被销毁。 C++ 不包含引用计数范例(尽管有 shared_ptr)。

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

因此,如果您的 myClass 实例也是静态创建的,那么您需要考虑它们之间的正常静态对象生命周期规则:

示例 #1

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

B t;
A B::a;

int main() {}

// Output: *B *A ~A ~B 

如您所见,B 的静态成员在 B 的实际实例之前被销毁。

示例 #2:

#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 

这里的情况正好相反。对于您当前的问题来说,这是一个廉价的解决方案,但我的建议是完全避免静态实例;你只会陷入更多像这样的静态初始化陷阱......可能会出现相同代码的未来化身!

There is no guarantee that static members are destroyed only after all instances of an object of the same class. C++ incorporates no reference counting paradigm (shared_ptr notwithstanding).

When considering lifetime, consider your static members as any other static object. There's really nothing binding them to their containing class other than being in the class's "namespace" (warning: not accurate terminology).

So, if your myClass instances are created statically too, then you need to consider normal static object lifetime rules between them:

Example #1:

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

B t;
A B::a;

int main() {}

// Output: *B *A ~A ~B 

As you can see, the static member of B is destroyed before the actual instance of B.

Example #2:

#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 

Here the reverse is true. It's a cheap fix for your current issue, but my advice is to avoid static instances altogether; you'll only fall into more static initialisation pitfalls like this down the line... possibly with a future incarnation of the same code!

旧街凉风 2024-11-13 08:49:18

如果您在静态方面遇到此类问题,则一定意味着 MyClass 也具有静态作用域,并且您不能设计这样的代码,让一个静态访问另一个静态。它可能有效,也可能无效,因为您对销毁顺序有疑问。

您也完全有可能有另一个全局(静态)导致内存损坏。如果是这种情况,则可能意味着覆盖一个全局变量可能会覆盖驻留在同一内存空间中的其他附近的全局变量,即您遇到问题的静态已损坏且未删除。

If you are having these kinds of problems with a static, it must mean that MyClass also has static scope and you can't design code like this with one static accessing the other. It might work and it might not work since you have a problem with the order of destruction.

It's also entirely possible that you have another global (static) causing memory corruption. If this is the case it might mean that overwriting one global might overwrite other near by globals residing in the same memory space, i.e. the static you are having problems with has been corrupted and not deleted.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文