C ++:std :: map <int,int>在被赋值时崩溃</int,int>

时间:2014-01-12 10:01:49

标签: c++

我正在尝试将int设置为int map,但程序崩溃了,我没有意识到原因。 我已经将问题总结为这个简短的简单代码。

当程序启动时,由于Utilities成员_instance是静态的 - 它通过转到其构造函数来初始化它,该构造函数包含一行:int到int(简单)映射赋值。但随后就崩溃了。

请注意,如果我评论该行,程序不会崩溃, 并且主要包含同一行。 所以我的两个问题是:

1)为什么会崩溃?这种行为背后有一点吗?

2)如何修复它以便我可以在构造函数中初始化地图?

谢谢

#include <map>

class Utilities
{
public:

    ~Utilities(){};
    static Utilities& instance();

private:
    Utilities();
    Utilities( const Utilities& ){};

    static Utilities _instance;
    static std::map<int, int> textIntToIntMap;
};


Utilities Utilities::_instance = Utilities();
std::map<int, int> Utilities::textIntToIntMap;

Utilities::Utilities()
{
    //The following line crashes, why?
    textIntToIntMap[1] = 2;
}

int main()
{
    static std::map<int, int> text2;
    text2[4] = 2;
    int xxx = 3;
}

5 个答案:

答案 0 :(得分:1)

问题是您在Utilities构建之前调用了Utilities::textIntToIntMap构造函数。

交换以下两行的顺序:

Utilities Utilities::_instance = Utilities();
std::map<int, int> Utilities::textIntToIntMap;

答案 1 :(得分:1)

您有初始化订单问题:

Utilities Utilities::_instance = Utilities();

此行调用Utilities的默认构造函数,然后尝试填充地图。但是现阶段没有初始化地图。

您应该设计您的代码以抵御此类初始化顺序问题。您可以通过在函数内创建静态实例来缓解其中的一些问题。这使您可以处理初始化的顺序。但是,定义的简单重新排序应该可以解决当前的问题:

std::map<int, int> Utilities::textIntToIntMap;
Utilities Utilities::_instance = Utilities();  // OK, map has been defined

答案 2 :(得分:0)

在初始化_instance之前,您需要在类外部定义map textTntIntMap。因为在构造函数中,您使用的是textIntToIntMap,它是一个静态成员,因此您需要先定义它。所以在课外使用以下几行:

std::map<int, int> Utilities::textIntToIntMap;
Utilities Utilities::_instance = Utilities();

答案 3 :(得分:0)

其他人已经发现在Utilities()之前构建了Utilities::textToIntMap。那么,现在的问题是:将来如何避免这些问题?

您可以使用函数返回对静态局部变量的引用,以确保在使用引用之前完成构造。您可以将此类函数放入命名空间。您还应该有一个方便的typedef,希望更短的名称,因此声明迭代器不是C ++ 98的断言。在C ++ 11上,无论如何你应该使用auto

请注意,在C ++ 98中使用全局或函数静态非POD数据是线程安全的。如果您希望安全地从多个线程使用textToMap(),并且不保证在第二个线程启动之前访问它,textToIntMap将需要在互斥锁中包装初始化。要大致了解如何执行此操作,请参阅Qt方便的Q_GLOBAL_STATIC中的inner function

在这种情况下,使用单例类似乎是毫无意义的Java主义。

Run a test on ideone

// Utilities.h
namespace Utilities {
  typedef std::map<int, int> Map;
  Map & textToIntMap();
}

// Utilities.cpp
namespace Utilities {
  namespace {
    struct InitializedMap : Map {
      InitializedMap() {
         insert(value_type(1, 2));
         // or
         (*this)[1] = 2;
      }
    };
  }
  Map & textToIntMap() {
    static InitializedMap map;
    return map;
  }
}

答案 4 :(得分:0)

试试这个::

#include <map>
#include <iostream>
using namespace std;

class Utilities
{
public:
    static Utilities& instance() {
        static Utilities instance;
        return instance;
    }
    ~Utilities(){};
    void PrintMapValues();
    void AddKeyValue(int key, int value);

private:
    Utilities();
    Utilities( const Utilities& ){};

    std::map<int, int> int_to_int_map_;
};

Utilities::Utilities()
{
    //The following line crashes, why?
    int_to_int_map_[-99] = 2;
}

void Utilities::PrintMapValues() {
    for(std::map<int, int>::iterator it = int_to_int_map_.begin(); it != int_to_int_map_.end(); ++it){
        cout << "Key:" << it->first << " Val:" << it->second << endl;
    }
}

void Utilities::AddKeyValue(int key, int value) {
    int_to_int_map_[key] = value;
}

int main()
{
    Utilities& utils = Utilities::instance();

    for (int i=0; i< 10; i++) {
        utils.AddKeyValue(i, i+20);
    }

    utils.PrintMapValues();

    return 0;
}