2009-05-16 2 views
2

У меня были большие проблемы с воспроизведением и обнаружением причины ошибки. Вступление кажется совершенно случайным, поэтому я где-то подозревал, что неинициализированная переменная. Но потом я нашел этот кусок кода:Может ли это вызвать неопределенное поведение?

CMyClass obj; // A 
obj.DoStuff(); 

if (somebool) 
{ 
    CMyClass obj; // B 
    obj.DoStuff(); 
} 

obj.DoOtherStuff(); 

Кажется, как будто DoOtherStuff() либо делается на «B», или что B.DoStuff() иногда на самом деле работает на A - то есть я DoStuff() является фактически вызвал первый объект.

Это могло случиться? Я не думаю, что у меня появилось предупреждение о компиляторе (теперь я исправил код, надеясь, что это может помочь). Похоже, очень, вероятно, что эта часть фактического кода - вот где ошибка, которую я пытаюсь найти, но, конечно, могут быть другие причины, которые я еще не обнаружил.

ответ

5

Код, как написано, должен работать. Первый вызов DoStuff() и последний звонок DoOtherStuff() могут быть отправлены только A.

Звонок DoStuff() внутри блока if(somebool) { } может быть отправлен только на B.

От standard:

3.3.2 локальной области

  1. Имя, объявленный в блоке (6.3) является локальным для этого блока. Его потенциальный объем начинается с момента его объявления (3.3.1), а заканчивается в конце его декларативной области.

И:

3.3.7 Имя скрывается

  1. Имя может быть скрыты от явного объявления того же имени в гнездовой декларативной области или производного класса (10.2).

Это сказанное, возможно, это не то, что было предназначен автором этого кода. Если переменные имеют одно и то же имя, возможно, цель состоит в том, чтобы иметь только один экземпляр этой переменной, а созданный внутри цикла экземпляр B является ошибкой. Прошли ли вы через логику, чтобы понять, имеет ли смысл второй экземпляр?

+0

Да, два экземпляра предназначались. – Srekel

+0

Интересно. Решение дать им одно и то же имя является подозрительным. Конечно, не видя логики, я понятия не имею, почему автор решил сделать это именно так. Переименовали ли они свои проблемы? –

+0

Я сомневаюсь, что их назвали то же самое было чем-то большим, чем «ошибка» для копирования-вставки. Я еще не тестировал код, поэтому не уверен, что он работает. – Srekel

1

Нет, этого не может быть.

Компилятор гарантирует, что объект B должным образом разрушен при выходе из области if, и, хотя он жив, действует на свое адресное пространство.

Ошибка в другом месте.

3

Если только obj.DoStuff() делает изменение в какой-то глобальный объект тогда, как Валентин указывает, что все должны быть самодостаточными в пределах, если заявление

+2

Возникают некоторые статические переменные класса. Или у них есть общий объект, который получается с какого-то завода. –

+1

@ Микола - хорошие моменты! – ChrisF

2

Локальные переменные с тем же именем, что и глобальная переменная скрывает глобальную переменную внутри этот блок. Однако глобальный оператор сферы (: :) может быть использован, чтобы сообщить компилятору вы имеете в виду глобальную версии

CMyClass obj; // A 
obj.DoStuff(); 
if (somebool) 
{ 
CMyClass obj; // B 
obj.DoStuff(); //does on B 
::obj.DoStuff(); //does on A 
} 
obj.DoOtherStuff(); //this will call A because B is destroyed 

Таким образом, локальная переменная B разрушается, когда он выходит из области видимости. Наличие локальных переменных с тем же именем, что и глобальные переменные, обычно является вызовом проблем, поэтому старайтесь избегать, когда это возможно.

2

Если вы используете GCC, вы можете (и, на мой взгляд, следует) использовать -Wshadow, который будет выдавать предупреждения в случаях, например, в вашем примере, что часто приводит к очень тонким ошибкам.

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

0

Ваш код может быть синтаксически правильным, но что делают методы? Например, переполнение стека может привести к появлению жужжащего поведения, например, если вы наблюдаете.

Смежные вопросы