为什么c++抛出异常的时候可以用左值引用接收右值?

为什么c++抛出异常的时候可以用左值引用接收右值?

void dowork() {
    //throw myexception();
    throw - 1;
}
int main() {
    try {
        dowork();
    }
    //catch (myexception &e) {//左值引用能接收临时对象?
    //    cout << "自定义异常" << endl;
    //}
    catch (int& i) {
        cout << "整型异常" << endl;
    }
    return 0;
    //myexception& e2 = myexception();
}

C++允许把右值用左值引用形式接受。这是由于C++采取了异常安全原则,即保证在抛出异常的情况下,程序状态可以保持平衡,而不会发生没有预料到的变动。这样,当出现异常的时候,左值的值就保持不变,右值的值也可以传递,防止函数调用时未经处理就抛出异常,而造成程序运行异常。

  • 这个问题的回答你可以参考下: https://ask.csdn.net/questions/7668285
  • 这篇博客你也可以参考下:为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数 考点:虚函数 析构函数
  • 除此之外, 这篇博客: 你的c++团队还在禁用异常处理吗?中的 异常处理的关键点 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    1. 不应该使用异常处理做什么?

      • throw仅用于抛出一个错误,标识函数没有按设想的方式去执行
      • 只有在知道可以处理错误时,才使用catch来捕获错误,例如转换类型或者内存分配失败
      • 不要使用throw来抛出编码错误,应该使用assert或者其它方法告诉编译器或者崩溃进程收集debug信息
      • 如果有必须要崩溃的事件,或者无法恢复的问题,不应该使用throw抛出,因为抛出来外部也无法处理,就应该让程序崩溃
      • try、catch不应该简单的用于函数返回值,函数的返回值应该使用return操作,不应该使用catch,这会给编程人员带来误解,同时也不应该用异常来跳出循环
    2. 异常处理看似简单好用,但它需要项目成员严格遵守开发规范,定好什么时候使用异常,什么时候不使用,而不是既使用异常又使用错误码方式。

    3. 构造函数可以抛出异常吗?可以而且建议使用异常,因为构造函数没有返回值,所以只能抛出异常,也有另一种办法就是添加一个成员变量标识对象是否构造成功,这种方法那就会额外添加一个返回该返回值的函数,如果定义一个对象数组那就需要对数组每个对象都判断是否构造成功,这种代码不太好。

    4. 构造函数抛出异常会产生内存泄漏吗?不会,构造函数抛出异常产生内存泄漏那是编译器的bug,已经在21世纪修复,不要听信谣言。

      void f() {
        X x;             // If X::X() throws, the memory for x itself will not leak
        Y* p = new Y();  // If Y::Y() throws, the memory for *p itself will not leak
      }
    5. 永远不要在析构函数中把异常抛出,还是拿对象数组举例,数组里有多个对象,如果其中一个对象析构过程中抛出异常,会导致剩余的对象都无法被析构,析构函数应该捕获异常并把他们吞下或者终止程序,而不是抛出。

    6. 构造函数内申请完资源后抛出异常怎么办?使用智能指针,关于char*也可以使用std::string代替。

      #include <memory>
      
      using namespace std;
      
      class SPResourceClass {
      private:
          shared_ptr<int> m_p;
          shared_ptr<float> m_q;
      public:
          SPResourceClass() : m_p(new int), m_q(new float) { }
          // Implicitly defined dtor is OK for these members,
          // shared_ptr will clean up and avoid leaks regardless.
      };
    7. 永远通过值传递方式用throw抛出异常,通过引用传递用catch来捕获异常。

    8. 可以抛出基本类型也可以抛出对象,啥都可以

    9. catch(...)可以捕获所有异常

    10. catch过程中不会触发隐式类型转换

    11. 异常被抛出,但是直到main函数也没有被catch,就会std::terminate()

    12. c++不像java,不会强制检查异常,throw了外层即使没有catch也会编译通过

    13. 异常被抛出时,在catch之前,try和throw之间的所有局部对象都会被析构

    14. 如果一个成员函数不会产生任何异常,可以使用noexcept关键字修饰

    15. 通过throw可以重新抛出异常

      int main() 
      { 
          try { 
              try  { 
                  throw 20; 
              } 
              catch (int n) { 
                   cout << "Handle Partially "; 
                   throw;   //Re-throwing an exception 
              } 
          } 
          catch (int n) { 
              cout << "Handle remaining "; 
          } 
          return 0; 
      }
  • 您还可以看一下 夏曹俊老师的C++微服务架构及安全云盘项目实训课程中的 完成了客户端的文件上传指令处理小节, 巩固相关知识点