Почему эта компиляция (используется в функции до инициализации)? - PullRequest
4 голосов
/ 09 апреля 2009

Рассмотрим этот код (использующий CString, потому что он знаком и его легко увидеть, когда он не создан, но ничего особенного в классе), протестированного в Visual Studio 2008:

CString DoSomething( const CString& sString )
{
    return sString;
}

CString sTest1 = DoSomething( sTest1 ); // Compiles (no warnings), fails at runtime
CString sTest2( DoSomething( sTest2 ) ); // Doesn't compile
CString sTest3; sTest3 = DoSomething( sTest3 ); // Compiles, self-assignment, works

Как я понимаю, стандарт C ++, Test1 может быть автоматически скомпилирован в Test2 как оптимизация во время компиляции, если доступен соответствующий конструктор (который по умолчанию будет сгенерирован так же, как и первый тест). Примечательно, однако, что поведение не совпадает с Test3, что будет работать правильно.

Теперь я понимаю, почему Test1 не работает и почему Test2 не компилируется. Что меня интересует, так это то, почему Test1 компилируется в первую очередь? Разрешено ли это в стандарте, открытом для интерпретации, в компиляторе VS2008, в статической проверке init-before-use или как? Есть ли способ заставить компилятор хотя бы выдать предупреждение в этом случае (Test1, по-видимому, компилирует чистый с максимальным уровнем предупреждения в соответствии с VS2008)? Что будет оправданием для спецификации C ++, разрешающей эту конструкцию?

Редактировать: В качестве альтернативы, есть ли способ заставить компилятор скомпилировать Test1 как Test2 (и таким образом вызвать ошибку)?

Изменить, чтобы добавить дословное сообщение об ошибке для Test2: ошибка C2065: 'sTest2': необъявленный идентификатор

Ответы [ 2 ]

4 голосов
/ 09 апреля 2009

Поведение, которое вы видите в sTest1, не определено в стандарте C ++. Это странно и неправильно, но компилируется на нескольких компиляторах.

См. Ответ litb в следующем потоке для получения более подробной информации: метод, выполняющийся на объекте ДО того, как объект был инициализирован?

3 голосов
/ 09 апреля 2009

В последние несколько дней было несколько вопросов о связанных явлениях.

Насколько я понимаю, что хотя sTest1 не инициализирован, он уже является действительным идентификатором (например, в C вы можете вызвать для него sizeof), он просто не имеет содержимого. Поэтому, когда вы делаете вызов DoSomething, вы передаете ссылку на неинициализированную переменную, которая является допустимой, но опасной.

Я предполагаю, что возвращение является проблемой во время выполнения, потому что вы пытаетесь выполнить возврат по значению (конструктор копирования) того, что по сути является неинициализированным пространством памяти, которое должно было быть строкой. В зависимости от того, как хранятся строки CStrings, код, вероятно, ищет нулевой терминатор или что-то, что представляет количество выделенных байтов.

...