带有和不带throw()的方法/构造函数签名中的c ++,用于自定义异常

时间:2017-09-02 07:27:33

标签: c++ class exception throw

我是c ++的初学者,因此为这个愚蠢的问题道歉。我在这里发帖是因为我在stackoverflow上找不到类似的答案。

我正在逐步使用C ++中的异常,并且我正在尝试使用自定义异常,我有这个代码

class MyException: public std::exception{
public:
    virtual const char* what() const throw() {
        return "something bad happened";
    }

};

// class that throws above exception

class canGoWrong {
public:
    canGoWrong(){
        throw MyException();
    }
};

上面的代码由老师展示。构造函数刚刚实现了基类exception中定义的虚函数。我到那儿了。

现在当我尝试使用不同版本进行练习时,我尝试使用自定义函数而不是重新定义虚拟(因为c ++没有严格执行接口的概念,如果我在这里错了,请纠正我。 )

我把它写成

class my_custom_shit_exception: public std::exception {
public:
    const char* show() { // I omitted the const throw() here
            return "This is an error encountered\n";
    }
};

class myclass {
public:
    myclass() {
        throw my_custom_shit_exception();
    }
};

总而言之,我没有发现两种方式的行为差异

public:
const char* show() {
        return "This is an error encountered\n";
}
virtual const char* what() const throw() {
    return "something bad happened";
}
  • 那么为什么在const throw()虚函数中使用了what()?它有什么不同?

感谢所有人。

2 个答案:

答案 0 :(得分:4)

我想展示Scott Meyers的一些引用

“Effective C ++”第三版

  

int doSomething() throw(); // note empty exception spec.

     

这并不是说doSomething永远不会抛出异常;它   如果doSomething抛出异常,那就是一个严重的错误,   并且应该调用意外的函数。 †

     

有关意外功能的信息,请咨询您最喜欢的搜索引擎或   全面的C ++文本。 (你可能有更好的运气搜索set_unexpected,   指定意外功能的函数。)

来自“Effective Modern C ++”

  

在C ++ 11中,无条件noexcept用于函数   这保证他们不会排放异常。

     

如果在运行时,异常离开f,则违反了f的异常规范。随着   在C ++ 98异常规范中,调用堆栈被解析为f的调用者,并且在一些之后   这里不相关的行动,程序执行终止。使用C ++ 11异常规范,运行时行为略有不同:堆栈只是可能的   在程序执行终止之前解除。   展开调用堆栈和可能展开调用堆栈之间的区别对代码生成产生了惊人的巨大影响。在noexcept函数中,优化器需要   如果异常传播,则不要将运行时堆栈保持在不可解除的状态   超出函数,也不必确保noexcept函数中的对象   按照构造的逆序销毁应该例外的功能。   具有“throw()”异常规范的函数缺乏这种优化灵活性,   和没有异常规范的函数一样。

答案 1 :(得分:3)

功能签名

#[macro_use]
extern crate nom;

use std::str;
use nom::IResult;

fn alternative<'a>(input: &'a [u8], alternatives: &Vec<String>) -> IResult<&'a [u8], &'a [u8]> {
    for alternative in alternatives {
        match tag!(input, alternative.as_bytes()) {
            done@IResult::Done(..) => return done,
            _ => () // continue
        }
    }
    IResult::Error(nom::ErrorKind::Tag) // nothing found.
}

fn main() {
    let months: Vec<String> = vec![
        "January", "February", "March", "April", "May", "June", "July",
        "August", "September", "October", "November", "December"
    ].into_iter().map(String::from).collect();

    fn print_res(r: IResult<&[u8],&[u8]>) {
        println!("{:?}", r);
        println!("{:?}\n", str::from_utf8(r.unwrap().1).unwrap());
    }
    print_res(alternative(b"May", &months));
    print_res(alternative(b"August", &months));
    print_res(alternative(b"NoGood", &months));
}

可以读作:private void HighlightRange(int originX, int originY, int range, bool greenRange = true) { if (range > 0) { List<Tuple<int, int>> hexCoordinates = new List<Tuple<int, int>>(); if (originX % 2 == 0) { hexCoordinates.Add(new Tuple<int, int>(originX, originY - 1)); hexCoordinates.Add(new Tuple<int, int>(originX - 1, originY - 1)); hexCoordinates.Add(new Tuple<int, int>(originX - 1, originY)); hexCoordinates.Add(new Tuple<int, int>(originX, originY + 1)); hexCoordinates.Add(new Tuple<int, int>(originX + 1, originY)); hexCoordinates.Add(new Tuple<int, int>(originX + 1, originY - 1)); } else { hexCoordinates.Add(new Tuple<int, int>(originX, originY - 1)); hexCoordinates.Add(new Tuple<int, int>(originX - 1, originY)); hexCoordinates.Add(new Tuple<int, int>(originX - 1, originY + 1)); hexCoordinates.Add(new Tuple<int, int>(originX, originY + 1)); hexCoordinates.Add(new Tuple<int, int>(originX + 1, originY + 1)); hexCoordinates.Add(new Tuple<int, int>(originX + 1, originY)); } hexCoordinates.RemoveAll(t => (t.Item1 < 0 || t.Item1 >= length || t.Item2 < 0 || t.Item2 >= height)); while (hexCoordinates.Count > 0) { if (range > 1) { HighlightRange(hexCoordinates[0].Item1, hexCoordinates[0].Item2, range - 1, greenRange); } if (greenRange) { gameField[hexCoordinates[0].Item1, hexCoordinates[0].Item2].IsGreenRange = true; } else { gameField[hexCoordinates[0].Item1, hexCoordinates[0].Item2].IsRedRange = true; } hexCoordinates.RemoveAt(0); } } else { return; } } class std::exception { //... public: virtual const char* what() const throw(); //... }; 的虚拟成员函数,它返回一个指向常量字符(数组)的指针,并且不会修改该对象的成员(因此第二个{{ 1}})并保证不在其代码中抛出异常。

请注意,异常规范现在已被弃用:相反,由于C ++ 11,有what说明符来声明函数&#34;保证&#34;不要抛出异常。此外,由于C ++ 17 std::exception已成为const的同义词,但行为略有不同。

有关详细信息,请参阅noexcept的{​​{3}}。

它还说:&#34;注意函数的noexcept规范不是编译时检查;它只是程序员通知编译器函数是否应抛出异常的方法。编译器可以使用此信息对非投掷函数进行某些优化[...]&#34;。