调用静态函数时c ++ globlal/stack实例ctor/dtor崩溃

Fra*_*ahm 2 c++ static-members

我有一个在main的同一个文件中定义的类,另一个类(完整的静态函数/成员)在2个单独的文件中定义,它崩溃了.我想这可能与全局/静态实例的生命周期有关.似乎在ctor中,静态成员尚未初始化,并且可能发生在退出时,静态成员在第一个实例被销毁之前被释放.这是测试代码:

    //testh.h
    #include <map>
    class Sc {
    public:
        static void insert();
        static void out();

    private:
        static std::map<int, int> map_;
    };

    //testcpp.cpp
    #include "testh.h"
    #include <iostream>
    std::map<int, int> Sc::map_;

    void Sc::insert() {
        map_.insert(std::make_pair(2,3));
    }

    void Sc::out() {
        for(auto m : map_) {
            std::cout << m.first << ' ' << m.second << '\n';
        }
    }

    //main.cpp
    #include "testh.h"
    class Nc {
    public:
        Nc() {
            Sc::insert();
            Sc::out();
        }
        ~Nc() {
            Sc::insert();
            Sc::out();
        }
    };

    Nc nc;
    int main() {

        system("pause");
        return 0;
    }
Run Code Online (Sandbox Code Playgroud)

以下是上述代码的一些奇怪行为:

如果我将staic成员替换为int,它不会崩溃,所以我想std :: map可能有问题?

如果我把所有代码都放到main.cpp中,它不会崩溃,但是这些代码不会生成相同的代码吗?

如果我不想做动态分配(新)如何解决这个问题?

Mar*_*ork 7

问题是你不知道将构造全局变量的顺序:

这个

// test.cpp
std::map<int, int> Sc::map_;
Run Code Online (Sandbox Code Playgroud)

还有这个

//main.cpp
Nc nc;
Run Code Online (Sandbox Code Playgroud)

因为它们在不同的编译单元中,所以标准不保证它们将被创建的顺序.因此,如果nc首先创建,则任何使用尝试都Sc::map_将失败(并且nc通过其对静态的调用来使用它).

将全局变量放入一个文件时:

//main.cpp
std::map<int, int> Sc::map_;
Nc nc;
Run Code Online (Sandbox Code Playgroud)

然后订单得到保证.这是宣言的顺序.所以只要你Sc::map_先放,那么一切都会奏效.

有一个简单的技术来解决这个问题::

替换这个:

private:
    static std::map<int, int> map_;
};
Run Code Online (Sandbox Code Playgroud)

附:

private:
    static std::map<int, int>& getMap()
    {
        static std::map<int, int> instance;
        return instance;
    }
};
Run Code Online (Sandbox Code Playgroud)

但真正的问题是你正在使用全局可变状态(全局变量).尽量不要使用它们.它将您的代码紧密绑定到globl状态.您应该将状态传递给具有参数的方法或通过知道如何检索状态的对象.

  • 我即将链接:http://www.parashift.com/c++-faq/static-init-order.html :) (3认同)