views:

2176

answers:

4

I have code like this:

class MapIndex
{
private:
    typedef std::map<std::string, MapIndex*> Container;
    Container mapM;

public:
    void add(std::list<std::tring>& values)
    {
        if (values.empty()) // sanity check
            return;

        std::string s(*(values.begin()));
        values.erase(values.begin());
        if (values.empty())
            return;

        MapIndex *mi = mapM[s];  // <- question about this line
        if (!mi)
            mi = new MapIndex();
        mi->add(values);
    }
}

The main concern I have is whether the mapM[s] expression would return reference to NULL pointer if new item is added to the map?

The SGI docs say this: *data_type& operator Returns a reference to the object that is associated with a particular key. If the map does not already contain such an object, operator[] inserts the default object data_type().*

So, my question is whether the insertion of default object data_type() will create a NULL pointer, or it could create an invalid pointer pointing somewhere in the memory?

+4  A: 

It'll create a NULL (0) pointer, which is an invalid pointer anyway :)

Mehrdad Afshari
I don't mind it being invalid, but want it to be "safe". You can easily check 0 pointer and you can call "delete" on it. Any reference (URL) to read about this?
Milan Babuškov
I don't have a reference at hand. But I'm pretty sure a pointer constructor will initialize it to 0 (just like all integral types, like `int`, `short`, ...).
Mehrdad Afshari
C++ Standard, 8.5 paragraph 5: 'To default-initialize an object of type T means: otherwise (neither non-POD nor array), the object is zero-initialized.' Just a couple of lines above: 'To zero-initialize an object of type T means: if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;' In the same standard, 3.9, paragraph 10: 'Arithmetic types (3.9.1), enumeration types, pointer types, and pointer to member types (3.9.2),[...] are collectively called scalar types.' So yes, a pointer will be default initialized to 0.
David Rodríguez - dribeas
Oh, BTW, I check with the current standard at hand, but there are drafts around (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf) where you can check some issues. Chances are you won't hit a dark spot where the final standard differs much from the draft. The standard can be bought on-line for about $30 (pdf)
David Rodríguez - dribeas
This behavior won't change in C++0x, as there is simply too much code which relies on this behavior.
MSalters
+2  A: 

The expression data_type() evaluates to a default-initialized object. In case of non-POD types, the default constructor is invoked, but in case of POD types, such as pointers, default initialization is equivalent to zero initialization.

So yes, you can rely on your map creating a NULL pointer. For an explanation, you can refer to Pseudo Constructor Initializers.

Bojan Resnik
+3  A: 

Yes it should be a zero (NULL) pointer as stl containers will default initialise objects when they aren't explicitly stored (ie accessing a non-existant key in a map as you are doing or resizing a vector to a larger size).

C++ Standard, 8.5 paragraph 5 states:

To default-initialize an object of type T means:

  • If T is a non-POD class type (clause class), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor)
  • If T is an array type, each element is default-initialized
  • Otherwise, the storage for the object iszero-initialized.

You should also note that default initialisation is different to simply ommiting the constructor. When you omit the constructor and simply declare a simple type you will get an indeterminate value.

int a; // not default constructed, will have random data 
int b = int(); // will be initialised to zero
Jamie Cook
+1  A: 

UPDATE: I completed my program and that very line I was asking about is causing it to crash sometimes, but at a later stage. The problem is that I'm creating a new object without changing the pointer stored in std::map. What is really needed is either reference or pointer to that pointer.

MapIndex *mi = mapM[s];  // <- question about this line
if (!mi)
    mi = new MapIndex();
mi->add(values);

should be changed to:

MapIndex* &mi = mapM[s];  // <- question about this line
if (!mi)
    mi = new MapIndex();
mi->add(values);

I'm surprised nobody noticed this.

Milan Babuškov