Подтвердить что ты не робот

Действительно ли передать nullptr на std::string:: assign?

У меня есть функция, которая возвращает указатель и длину, и я хочу вызвать std::string::assign(pointer, length). Должен ли я делать специальный случай (вызов clear), когда длина равна нулю, а указатель может быть nullptr?

В стандарте С++ говорится:

21.4.6.3 basic_string::assign

basic_string& assign(const charT* s, size_type n);
Requires: s points to an array of at least n elements of charT.

Итак, что, если n равно нулю? Что такое массив нулевых символов и как он указывает на него? Действительно ли для вызова

s.assign(nullptr, 0);

или это поведение undefined?

Реализация libstdС++, по-видимому, не вызывает разыменования указателя s, когда размер n равен нулю, но это вряд ли гарантирует.

4b9b3361

Ответ 1

Педантически, nullptr не соответствует требованиям указания массива размера >=0, и поэтому стандарт не гарантирует поведение (это UB).

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

Вышеприведенное рассуждение не означает, что ОК игнорировать UB. Но, если нет причин для отказа от s.assign(nullptr, 0), тогда было бы предпочтительнее изменить формулировку стандарта на "Если n больше нуля, то s указывает на...". Я не знаю никаких веских оснований, чтобы запретить это, но я не могу пообещать, что разумной причины не существует.

Обратите внимание, что добавление проверки вряд ли сложно:

s.assign(ptr ? ptr : "", n);

Что представляет собой массив нулевых символов

Это: new char[0]. Массивы автоматического или статического хранения могут не иметь нулевого размера.

Ответ 2

Хорошо, как вы указываете, стандарт говорит: "s указывает на массив...". Нулевой указатель не указывает на массив любого количества элементов. Даже не 0 элементов. Также обратите внимание, что s указывает на "массив по крайней мере n элементов...". Поэтому ясно, что если n равно нулю, вы все равно можете передать законный указатель на массив.

В целом, API std::string не хорошо защищен от нулевых указателей до charT. Поэтому вы всегда должны быть уверены, что указатели, которые вы передаете, не равны нулю.

Ответ 3

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

Тем не менее, я бы ошибался в стороне осторожности. Вы можете утверждать, что вы не отвечаете требованиям стандартов:

21.4.6.3 basic_string:: присвойте

8 Требует: s указывает на массив из не менее n элементов charT

потому что nullptr не указывает на массив.

Так технически поведение undefined.

Ответ 4

Из стандарта (2.14.7) [lex.nullptr]:

Литералом указателя является ключевое слово nullptr. Это значение типа std::nullptr_t. [ Примечание: std::nullptr_t- это отдельный тип, который не является ни указательным типом, ни указателем на тип члена...]

std::nullptr_t может быть неявно преобразован в любой тип нулевого указателя согласно 4.10.1 [conv.ptr]. Независимо от типа нулевого указателя факт остается фактом, что он ничего не указывает.

Таким образом, он не удовлетворяет требованию о том, что s указывает на массив из не менее n элементов charT.

Кажется, что это поведение undefined.

Интересно, что в соответствии с этим ответом в стандарте С++ 11 четко указано, что s не должен быть нулевым указателем в конструкторе basic_string, но с тех пор эта формулировка была удалена.