Какой конструктор по умолчанию для указателя C ++? - PullRequest
27 голосов
/ 02 июня 2009

У меня есть такой код:

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

public:
    void add(std::list<std::string>& 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);
    }
}

Основная проблема, с которой я столкнулся, заключается в том, будет ли выражение mapM [s] возвращать ссылку на указатель NULL, если новый элемент будет добавлен на карту?

Документы SGI говорят это: data_type & operator [] (const key_type & k) Возвращает ссылку на объект, связанный с определенным ключом. Если карта еще не содержит такого объекта, оператор [] вставляет объект по умолчанию data_type ().

Итак, мой вопрос заключается в том, будет ли вставка объекта по умолчанию data_type () создать указатель NULL или он может создать недопустимый указатель, указывающий где-то в памяти?

Ответы [ 5 ]

22 голосов
/ 02 июня 2009

Будет создан указатель NULL (0), который в любом случае является недопустимым указателем:)

18 голосов
/ 02 июня 2009

Да, это должен быть нулевой (NULL) указатель, так как контейнеры stl будут инициализировать объекты по умолчанию, когда они не сохранены явно (т.е. получают доступ к несуществующему ключу на карте, как вы делаете, или изменяете размер вектора до большего размера). ).

Стандарт C ++, пункт 8 8.5 гласит:

Для инициализации по умолчанию объекта тип Т означает:

  • Если T является типом класса не POD (классом предложения), по умолчанию конструктор для T называется (а инициализация плохо сформирована, если T имеет нет доступного конструктора по умолчанию)
  • Если T является типом массива, каждый элемент инициализируется по умолчанию
  • В противном случае хранилище для объекта инициализируется нулями.

Следует также отметить, что инициализация по умолчанию отличается от простого пропуска конструктора. Когда вы опускаете конструктор и просто объявляете простой тип, вы получите неопределенное значение.

int a; // not default constructed, will have random data 
int b = int(); // will be initialised to zero
3 голосов
/ 09 июня 2009

ОБНОВЛЕНИЕ: Я завершил свою программу, и та самая строка, о которой я спрашивал, иногда вызывает ее сбой, но на более позднем этапе. Проблема в том, что я создаю новый объект без изменения указателя, хранящегося в std :: map. Что действительно нужно, так это либо ссылка, либо указатель на этот указатель.

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

следует изменить на:

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

Я удивлен, что никто не заметил этого.

2 голосов
/ 02 июня 2009

Выражение data_type() оценивается как объект, инициализированный по умолчанию. В случае типов, отличных от POD, вызывается конструктор по умолчанию, но в случае типов POD, таких как указатели, инициализация по умолчанию эквивалентна нулевой инициализации.

Так что да, вы можете положиться на свою карту, создав указатель NULL. Для объяснения вы можете обратиться к Инициализаторам псевдо-конструктора .

0 голосов
/ 17 ноября 2010

Не уверен насчет сбоя, но определенно утечка памяти, как это утверждение

if (! Mi) mi = new MapIndex ();

всегда возвращает true, потому что указатель mi не является ссылкой на то, что содержит mapM для конкретного значения с.

Я бы также не использовал обычные указатели и использовал boost :: shared_ptr или некоторые другие другой указатель, который освобождает память при уничтожении. Это позволяет вызывать mapM.clear () или erase () который должен вызывать деструкторы ключей и значений, хранящихся на карте. Что ж, если значением является POD, например указатель, то для него не вызывается деструктор, если он не удален вручную в то время как перебор всей карты приведет к утечкам памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...