Как другие сказали, Вы не можете надежно обнаружить недопустимый указатель. Рассмотрите некоторые формы, которые мог бы принять недопустимый указатель:
у Вас мог быть нулевой указатель. Это - то, на которое Вы могли легко проверить и сделать что-то о.
у Вас мог быть указатель на где-нибудь за пределами допустимой памяти. То, что составляет допустимую память, варьируется в зависимости от того, как среда выполнения Вашей системы настраивает адресное пространство. В системах Unix это обычно - виртуальное адресное пространство, запускающееся в 0 и идущее в некоторое большое количество мегабайтов. Во встроенных системах это могло быть довольно маленьким. Это не могло бы запуститься в 0 в любом случае. Если Ваше приложение, оказывается, работает в привилегированном режиме или эквиваленте, то Ваш указатель мог бы сослаться на действительный адрес, который может или не может быть сохранен с реальной памятью.
у Вас мог быть указатель на где-нибудь в Вашей допустимой памяти, даже в Вашем сегменте данных, bss, стеке или "куче", но не указывающий на доступный объект. Вариант этого является указателем, который раньше указывал на доступный объект, прежде чем что-то плохо произошло с объектом. Плохие вещи в этом контексте включают освобождение, повреждение памяти или повреждение указателя.
у Вас могло быть утончение недопустимого указателя, такого как указатель с недопустимым выравниванием для ссылаемой вещи.
проблема становится еще хуже, когда Вы рассматриваете основанную на сегменте/смещении архитектуру и другие нечетные реализации указателя. Этот вид вещи обычно скрыт от разработчика хорошими компиляторами и разумным использованием типов, но если Вы хотите проникнуть в завесу и попытаться перехитрить операционную систему и разработчиков компилятора, ну, в общем, Вы можете, но нет одного универсального способа сделать это, который обработает все проблемы, с которыми Вы могли бы столкнуться.
лучшая вещь, которую можно сделать, позволяют катастрофический отказ и производят некоторую хорошую диагностическую информацию.
Следующий код следует считать плохим тоном, независимо от языка или желаемой функциональности:
while( true ) {
}
Цикл while (true)
является плохой формой, потому что он:
while (true)
для циклов, которые являются не бесконечно, мы теряем способность кратко общаться, когда циклы фактически не имеют условия завершения. (Возможно, это уже произошло, поэтому вопрос спорный.) Следующий код является лучшей формой:
while( isValidState() ) {
execute();
}
bool isValidState() {
return msg->state != DONE;
}
Нет флага. Нет goto
. Без исключения. Легко поменять. Легко читать. Легко исправить. Дополнительно код:
Второй момент важен. Не зная, как работает код, если кто-то попросит меня сделать так, чтобы основной цикл позволял другим потокам (или процессам) иметь некоторое время ЦП, на ум приходят два решения:
Легко вставьте паузу:
while( isValidState() ) {
execute();
sleep();
}
Выполнение переопределения:
void execute() {
super->execute();
sleep();
}
Этот код проще (а значит, его легче читать), чем цикл со встроенным переключателем
. Метод isValidState
должен только определять, следует ли продолжать цикл. Рабочую лошадку метода следует абстрагировать в методе execute
,
while True:
choice = raw_input('What do you want? ')
if choice == 'restart':
continue
else:
break
print 'Break!'
Versus:
choice = 'restart';
while choice == 'restart':
choice = raw_input('What do you want? ')
print 'Break!'
Здесь , а True
приводит к вводящему в заблуждение и слишком сложному коду.
Вы можете потенциально использовать goto, но я бы предпочел установить флаг, который останавливает петля. Затем выйдите из переключателя.
В C ++ нет конструкции для выхода из цикл в данном случае.
Либо используйте флаг, чтобы прервать цикл, либо (при необходимости) извлеките свой код в функцию и используйте return
.
Насколько я знаю, в C ++ нет «двойного разрыва» или аналогичной конструкции. Наиболее близким будет goto
, который, хотя и имеет плохую коннотацию в своем названии, существует в языке по какой-то причине - пока он используется осторожно и экономно, это жизнеспособный вариант.
Изящный способ сделать это - поместить это в функцию:
int yourfunc() {
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
return;
}
}
}
Необязательно (но «плохие методы»): как уже предлагалось, вы можете использовать goto или выбросить исключение внутри переключателя.
Вы можете использовать goto
.
while ( ... ) {
switch( ... ) {
case ...:
goto exit_loop;
}
}
exit_loop: ;
Даже если вам не нравится goto, не используйте исключение для выхода из цикла. Следующий пример показывает, насколько это может быть некрасиво:
try {
while ( ... ) {
switch( ... ) {
case ...:
throw 777; // I'm afraid of goto
}
}
}
catch ( int )
{
}
Я бы использовал goto
как в этот ответ. В этом случае goto
сделает код более понятным, чем любой другой вариант. Я надеюсь, что этот вопрос будет полезен.
Но я думаю, что использование goto
- единственный вариант здесь из-за строки while (true)
. Вам следует подумать о рефакторинге вашего цикла. Я бы предположил следующее решение:
bool end_loop = false;
while ( !end_loop ) {
switch( msg->state ) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
end_loop = true; break;
}
}
Или даже следующее:
while ( msg->state != DONE ) {
switch( msg->state ) {
case MSGTYPE: // ...
break;
// ... more stuff ...
}
Вы можете поместить свой переключатель в отдельную функцию, например это:
bool myswitchfunction()
{
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
return false; // **HERE, I want to break out of the loop itself**
}
return true;
}
while(myswitchfunction())
;
Если я хорошо помню синтаксис C ++, вы можете добавить метку к операторам break
, как и для goto
. То, что вы хотите, легко написать:
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
break outofloop; // **HERE, I want to break out of the loop itself**
}
}
outofloop:
// rest of your code here
Альтернативное решение - использовать ключевое слово continue
в сочетании с break
, то есть:
for (;;) {
switch(msg->state) {
case MSGTYPE
// code
continue; // continue with loop
case DONE:
break;
}
break;
}
Используйте continue
оператор для завершения каждой метки case, в которой вы хотите продолжить цикл, и используйте оператор break
для завершения меток case, которые должны завершить цикл.
Конечно, это решение работает только в том случае, если нет дополнительного кода для выполняется после оператора switch.
Самый простой способ сделать это - поставить простой IF перед выполнением SWITCH, и этот IF проверяет ваше условие выхода из цикла .......... настолько просто, насколько это возможно