views:

61

answers:

2

Hi all,

I have the following function as the constructor for a class:

template<typename T>
void Pointer<T>::Pointer(T* inPtr)
{
  mPtr = inPtr;
  if (sRefCountMap.find(mPtr) == sRefCountMap.end()) {  
    sRefCountMap[mPtr] = 1;
  } else {
    sRefCountMap[mPtr]++;
  }
}

Here is the definition for the map:

static std::map<T*, int> sRefCountMap;

I get a Bus Error sometimes when this code is run:

#0  0x95110fc0 in std::_Rb_tree_decrement ()
#1  0x00017ccc in std::_Rb_tree_iterator<std::pair<Language::Value* const, int> >::operator-- (this=0xbfffe014) at stl_tree.h:196
#2  0x0001b16c in std::_Rb_tree<Language::Value*, std::pair<Language::Value* const, int>, std::_Select1st<std::pair<Language::Value* const, int> >, std::less<Language::Value*>, std::allocator<std::pair<Language::Value* const, int> > >::insert_unique (this=0x2a404, __v=@0xbfffe14c) at stl_tree.h:885
#3  0x0001b39c in std::_Rb_tree<Language::Value*, std::pair<Language::Value* const, int>, std::_Select1st<std::pair<Language::Value* const, int> >, std::less<Language::Value*>, std::allocator<std::pair<Language::Value* const, int> > >::insert_unique (this=0x2a404, __position={_M_node = 0x2a408}, __v=@0xbfffe14c) at stl_tree.h:905
#4  0x0001b5a0 in __gnu_norm::map<Language::Value*, int, std::less<Language::Value*>, std::allocator<std::pair<Language::Value* const, int> > >::insert (this=0x2a404, position={_M_node = 0x2a408}, __x=@0xbfffe14c) at stl_map.h:384
#5  0x0001b6e0 in __gnu_norm::map<Language::Value*, int, std::less<Language::Value*>, std::allocator<std::pair<Language::Value* const, int> > >::operator[] (this=0x2a404, __k=@0x2e110) at stl_map.h:339

Thanks.

+1  A: 

You have likely corrupted your heap somewhere else in your program. Run your program through a memory debugger (e.g. valgrind) and figure out where the corruption is occurring.

Tyler McHenry
Mike's answer is more likely now that you said it's a static `Pointer`. When there's no static initialization involved, however, a mysterious crash within a standard library class or function is nearly always a heap corruption issue.
Tyler McHenry
+6  A: 

From your comments, you say that you're initialising a static Pointer. This most likely means you've encountered the "static initialisation order fiasco" - if two static objects are in different compilation units, then it's not defined which order they're initialised in. So if the constructor of one depends on the other already being initialised, then you might get away with it, or you might not. Sod's Law dictates that the code will work during testing, then mysteriously break when it's deployed.

The best solution is to avoid static objects; they're rarely a good idea.

Another possibility is lazy instantiation, something like this:

typedef std::map<T*, int> RefCountMap;

static RefCountMap& GetRefCountMap()
{
    static RefCountMap map;
    return map;
}

This may have issues of it's own; it's guaranteed to be constructed before it's used, but might be destroyed before you've finished with it, if a static destructor accesses it, and there may be thread safety issues. For the gory details, see the many discussions on the Singleton pattern, which requires a static instance. Singletons in C++ are a whole world of pain, best avoided if possible.

Mike Seymour
FWIW, that's just a nice global variable, not a singleton (you aren't preventing the creation of further `RefCountMap`'s). However, I think this global solution is far superior to a singleton.
GMan
@GMan: you're right; I've edited to improve the terminology.
Mike Seymour