Целочисленная константа 0 заставляет std::string выбрасывать

Я столкнулся со сбоем среды выполнения в Visual Studio 2017 в файле minkernel\crts\ucrt\src\appcrt\string\i386\strlen.asm после изменения функции. Вот ситуация в качестве минимального примера в Compiler Explorer:

#include <string>

//void func(int i); // Original function signature
void func(const std::string& str); // New function signature: 'int' parameter changed to 'std::string'

int square(int num) {
    func(0); // This implicit conversion of '0' to 'any pointer'
    //func(1); // This doesn't compile anymore, which is expected
    //func((void*) 0); // This doesn't compile, why?
}

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

Пояснения: изначально у моей функции был целочисленный параметр. Я реорганизовал его, чтобы принять параметр std::string, и использовал «Compile», чтобы компилятор нашел все вызовы и сообщил о них как об ошибках для меня; Поэтому я просмотрел каждый из них и исправил их. Например, func(1); больше не компилируется, так как заменено на func("1");.

Однако с вызовами func(0); произошло нечто неожиданное: они не вызвали никаких ошибок во время компиляции, а вместо этого вылетели во время выполнения! По-видимому, в С++ все еще существует невидимое/автоматическое преобразование целочисленной константы 0 в загадочный тип указателя. Похоже, это не void *, так как func((void*) 0); не компилируется.

Вопрос. Есть ли способ отключить этот автоматический процесс? Или вы можете помочь мне понять, что происходит по стандарту и почему?


person Remz    schedule 19.12.2019    source источник
comment
0, помимо того, что является целым числом, является константой нулевого указателя. Он может быть преобразован в указатель любого типа. Если вы приведете его к const char*, вы получите ту же проблему: он вызывает конструктор std::string, который принимает const char*, и передача нулевого указателя этому конструктору приводит к неопределенному поведению.   -  person Pete Becker    schedule 19.12.2019
comment
MSVC (анализ кода): предупреждение C6387: «_Param_(1)» может быть «0»: это не соответствует спецификации функции «std::basic_string‹char,std::char_traits‹char›,std:: распределитель‹char› ›::{ctor}'.   -  person Adrian Mole    schedule 19.12.2019
comment
Приятно знать, что я никогда не использовал функцию анализа кода в MSVC. Хотя это правда, что он действительно обнаруживает это, было бы неплохо, если бы сам Стандарт сделал это ошибкой времени компиляции, удалив эту древнюю константу 0. Теперь у нас есть nullptr начиная с С++ 11. Тоже 10 лет. Странно, что однострочная программа вроде: std::string crash_global(0); ставит на колени могучий С++. Даже с -Wall -Wextra это ни о чем не говорит.   -  person Remz    schedule 20.12.2019
comment
@PeteBecker: я чувствую, что я не собирался быть дубликатом Почему не std::string принимает нулевой указатель?. Возможно, мне следовало сформулировать это более точно: почему стандарт С++ по-прежнему позволяет считать constant 0 указателем вместо того, чтобы полагаться на типобезопасный nullptr, который существует со времен С++ 11?   -  person Remz    schedule 20.12.2019
comment
@Remz - причина того, что он по-прежнему разрешен, заключается в том, что он широко используется, и для его изменения потребуется переписать много кода.   -  person Pete Becker    schedule 20.12.2019
comment
@PeteBecker: Действительно, но должна ли быть опция компилятора, чтобы новые программы применяли и переставали полагаться на этот старый остаток?   -  person Remz    schedule 21.12.2019