Ответ 1
Он создаст указатель NULL
(0), который в любом случае является недопустимым указателем:)
У меня такой код:
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 docs говорят об этом: data_type & operator [] (const key_type & k) Возвращает ссылку на объект, связанный с определенным ключом. Если в карте нет такого объекта, оператор [] вставляет объект по умолчанию data_type().
Итак, мой вопрос заключается в том, будет ли вставка объекта по умолчанию data_type() создать указатель NULL или создать недопустимый указатель, указывающий где-нибудь в памяти?
Он создаст указатель NULL
(0), который в любом случае является недопустимым указателем:)
Да, он должен быть нулевым (NULL) указателем, поскольку контейнеры stl будут инициализировать объекты по умолчанию, если они явно не сохранены (т.е. доступ к несуществующему ключу на карте по мере того, как вы делаете или изменяете размер вектора в большем размере).
Стандарт С++, пункт 8.5 пункта 5:
По умолчанию инициализируется объект тип T означает:
- Если T - тип класса не-POD (класс предложения), значение по умолчанию конструктор для T называется (и инициализация плохо сформирована, если T имеет нет доступного конструктора по умолчанию)
- Если T - тип массива, каждый элемент инициализируется по умолчанию
- В противном случае хранилище для объекта iszero-initialized.
Вы также должны заметить, что инициализация по умолчанию отличается от простого конструктора. Когда вы опускаете конструктор и просто объявляете простой тип, вы получите неопределенное значение.
int a; // not default constructed, will have random data
int b = int(); // will be initialised to zero
ОБНОВЛЕНИЕ: Я завершил свою программу, и эта строка, о которой я спрашивал, вызывает ее иногда, но на более позднем этапе. Проблема в том, что я создаю новый объект без изменения указателя, хранящегося в 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);
Я удивлен, что никто этого не заметил.
Выражение data_type()
оценивается объектом, инициализированным по умолчанию. В случае не-POD-типов вызывается конструктор по умолчанию, но в случае типов POD, таких как указатели, инициализация по умолчанию эквивалентна нулевой инициализации.
Итак, вы можете положиться на свою карту, создав указатель NULL
. Для объяснения вы можете обратиться к Инициализаторы псевдоконструктора.
Не уверен в сбое, но определенно утечка памяти, как это утверждение
если (! mi) mi = new MapIndex();
всегда возвращает true, потому что указатель mi не ссылается на то, что mapM удерживает для частного значения s.
Я бы также избегал использования обычных указателей и использовал boost:: shared_ptr или некоторые другой указатель, который освобождает память при уничтожении. Это позволяет вызвать mapM.clear() или стереть() который должен вызывать деструкторы ключей и значений, хранящихся на карте. Ну, если значение POD, например, ваш указатель, тогда никакой деструктор не вызывается для этого, если только ручное удаление в то время как повторение всей карты приведет к утечке памяти.