2016-02-05 79 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)抱怨富到达没有返回结束(-Wreturn-type) 有没有办法说服编译器,一切正常,没有隐藏警告呢?

+0

_是否有办法让编译器确信一切正常,而不会将警告隐藏起来?_是不是不相交? – erip

+0

多态异常?为什么?派生自'std :: runtime_error'或'std :: logic_error'。然后抛出你想抛出的异常 - 每个问题类型一个异常类型。 –

+0

@erip:它们不是不相交的,因为一切都确实没问题,如果我将raise函数的throw语句带到body中,编译器会认识到所有的执行路径都会正确返回。如果它隐藏在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++关键字)。 (因为你没有提到编译器抱怨总是这样的情况)。

显而易见的解决方案是在抛出异常之后添加return语句。

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

另一种方法是调整你的代码,所以总有一个返回路径

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

这样,编译器可以检测到每个执行路径,有一个有效的return语句。

+0

这对我来说似乎是最合理的。 – erip

+0

确实,第二种选择可能是唯一合理的方法。 我曾考虑过第一种选择,但我不喜欢“间谍价值”,即使它们从未实际使用过。这就是为什么我特意说“一种干净的方式” – Triskeldeian