Является ли значение по умолчанию для nullptr в карте указателей определенного поведения?

Следующий код, кажется, всегда следует за истинной ветвью.

#include <map>
#include <iostream>

class TestClass {
// implementation
}

int main() {
std::map<int, TestClass*> TestMap;
if (TestMap[203] == nullptr) {
std::cout << "true";
} else {
std::cout << "false";
}
return 0;
}

Определено ли поведение неинициализированного указателя, указывающего на nullptrили артефакт моего компилятора?

Если нет, как я могу обеспечить переносимость следующего кода? В настоящее время я использую похожую логику, чтобы вернуть правильный экземпляр Singleton для log file:

#include <string>
#include <map>

class Log {
public:
static Log* get_instance(std::string path);
protected:
Log(std::string path) : path(path), log(path) {};
std::string path;
std::ostream log;
private:
static std::map<std::string, Log*> instances;
};

std::map<std::string, Log*> Log::instances = std::map<std::string, Log*>();

Log* Log::get_instance(std::string path) {
if (instances[path] == nullptr) {
instances[path] = new Log(path);
}
return instances[path];
}

Одним из решений будет использовать что-то похожее на это где вы используете специальную функцию, предоставьте значение по умолчанию при проверке map, Тем не менее, я понимаю, что это приведет к сложности поиска O(n) вместо O(1), Это не слишком большая проблема в моем сценарии (было бы только несколько журналов), но лучшим решением было бы как-то заставить указатели типа Log* ссылаться nullptr по умолчанию выполняется проверка соответствия O(1) и портативный одновременно. Возможно ли это, и если да, то как бы я это сделал?

6

Решение

Карта всегда инициализирует значения своих членов (конечно, в ситуациях, когда они не инициализируются копированием), а инициализация значения для встроенных типов означает инициализацию с нуля, поэтому это действительно определенное поведение. Это особенно верно для части значения новых ключей, генерируемых при доступе к элементам с operator[] который не существовал до того, как называть это.

Обратите внимание, что неинициализированный указатель не обязательно нулевой указатель; действительно, простое чтение его значения уже вызывает неопределенное поведение (и может привести к ошибке сегментации на определенных платформах при определенных обстоятельствах). Дело в том, что указатели на картах не неинициализированный. Так что если вы напишите, например,

void foo()
{
TestClass* p;
// ...
}

p будут не быть инициализирован в nullptr,

Однако обратите внимание, что вы можете вместо этого проверить наличие, чтобы избежать накопления ненужных записей. Вы бы проверить наличие, используя find функция-член:

map<int, TestClass*>::iterator it = TestMap.find(203);
if (it == map.end())
{
// there's no such element in the map
}
else
{
TestClass* p = it->second;
// ...
}
9

Другие решения

Да, это определенное поведение. Если элемент еще не находится на карте, когда вы получаете к нему доступ через operator[], он получает по умолчанию построен.

1

По вопросам рекламы [email protected]