2016-02-05 2 views
0

У меня есть небольшая проблема, которую я не могу решить чистым способом. Я немного экспериментирую с обработкой полиморфных исключений, поэтому добавил виртуальную функцию рейза в свой класс исключений, которые выполняют фактическое бросание, и я заменил бросок вызовом raise(). Все работает, как ожидалось, но затем я применил это решение функции с типом возвращаемого со следующей общей форме:Полиморфная обработка исключений и предупреждения компилятора

Obj Foo() 
{ 
    if(true) 
    return Obj 
    else 
    { 
    //throw Exception; //With this call everything is fine 
    Exception e{}; 
    e.raise(); //The compiler warns me that I do not return anything 
    } 
} 

Когда я компилирую такую ​​функцию в GCC компилятора (v4.9) жалуется, что Foo достигает конец (без возврата) (-Дервый тип) Есть ли способ убедить компилятор, что все в порядке, не скрывая предупреждения?

+0

_I есть ли способ убедить компилятор, что все в порядке, не скрывая предупреждения? _ Разве эти непересекающиеся? – erip

+0

Полиморфные исключения? Зачем? происходят из 'std :: runtime_error' или' std :: logic_error'. Затем выведите исключение, которое вы хотите бросить, - один тип исключения для типа проблемы. –

+0

@erip: они не являются непересекающимися, потому что все на самом деле нормально. Если я беру инструкцию throw из функции повышения в тело, компилятор распознает, что все пути выполнения возвращаются должным образом. Если он скрыт в функции raise(), компилятор жалуется на – Triskeldeian

ответ

1

Чтобы избежать этого, вы можете сделать каждый путь управления в функции возвратом чего-то, что согласуется с типом возвращаемого значения, даже если некоторые условные выражения могут быть всегда показаны, или некоторые пути могут отображаться всегда, чтобы генерировать исключения. Здесь ваш путь else не имеет возвращаемого значения типа Obj.

Таким образом, после вашего e.raise() вы можете вернуть некоторое значение. Если невозможно создать подходящее значение, подумайте о возврате функции optional<obj>.

+1

«каждый путь управления должен что-то вернуть ...» - нет, это не требуется. Только если возвращаемое значение ** используется **, функция должна вернуть что-то разумное.Нет ничего плохого в выходе из функции путем исключения исключения, независимо от того, выполняется ли это «throw» или вызовом функции, целью которого является выброс исключения. Проблема здесь - слишком полезный компилятор, который применяет не-правила. –

+0

Спасибо, @PeteBecker Я думаю, вы правы. Будет соответствующим образом обновляться. –

+0

@Pete Becker: +1. Дело только в том, что компилятор фактически не применяет ограничение, а просто предупреждает. Тем не менее, вы правы – Triskeldeian

1

Если вам не нужна портативность, и с помощью расширений компилятора GCC являются хорошо, то вы можете использовать gcc noreturn function attribute, который работает с функциями C и C++:

class Exception { 

// ... 

    void raise() __attribute__ ((noreturn)); 

}; 
+0

Я стараюсь держать портативный, но хорошо знать, спасибо – Triskeldeian

2

Я предполагаю, что Exception.raise() бросает исключение, и что вы используете true для представления некоторого выражения, которое определяет, не следует ли генерировать исключение (а не ключевое слово C++). (поскольку вы не упомянули компилятор, жалующийся на условие, которое всегда верно).

Очевидное решение состоит в том, чтобы добавить оператор возврата после выброса исключения.

Exception e{}; 
e.raise(); 
return Obj; // this will not be reached 

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

if (!true) 
{ 
    Exception e{}; 
    e.raise();  // or, alternatively, throw e 
} 
return Obj; 

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

+0

Это кажется мне самым разумным. – erip

+0

Действительно, второй вариант, вероятно, единственный разумный путь. Я думал о первом варианте, но мне не нравятся «значения шпиона», даже если они никогда не используются. Вот почему я специально сказал «чистый путь», – Triskeldeian