C++ c++;异常处理按引用传递:抛出的地址与捕获的地址不同?

C++ c++;异常处理按引用传递:抛出的地址与捕获的地址不同?,c++,C++,问题:您是否看到addr1和addr2是不同的,知道为什么吗?当抛出异常时,会生成一个副本。您正在查看该副本的地址 (处理程序的异常怎么可能有相同的地址?当您抛出时,您退出了包含异常的块,因此它不再存在。您无法访问不存在的内容。)这很有意义。异常在抛出时被复制,这样它就可以在退出其源的堆栈帧后继续存在。一旦该异常退出它起源的{}块,该堆栈帧将弹出,其中的所有局部变量都将消失。因此必须进行复制。仅在通过值的情况下进行复制,对吗,但是在这里我粘贴了使用pass-by-reference的代码。thr

问题:您是否看到addr1和addr2是不同的,知道为什么吗?

当抛出异常时,会生成一个副本。您正在查看该副本的地址


(处理程序的异常怎么可能有相同的地址?当您抛出时,您退出了包含异常的块,因此它不再存在。您无法访问不存在的内容。)

这很有意义。异常在抛出时被复制,这样它就可以在退出其源的堆栈帧后继续存在。一旦该异常退出它起源的
{}
块,该堆栈帧将弹出,其中的所有局部变量都将消失。因此必须进行复制。

仅在通过值的情况下进行复制,对吗,但是在这里我粘贴了使用pass-by-reference的代码。
throw
是创建副本的原因。您正在捕获一个引用,但它是对由
throw
@SamJ创建的副本的引用:您没有抓住要点。有两个不同的对象,本地对象
myex
,它位于函数堆栈中,抛出对象(抛出表达式从堆栈复制到编译器定义的位置)。然后,如果您通过值捕获异常,则会执行从抛出对象到捕获异常的函数堆栈的第二次复制。请注意,必须保留原始异常,以防
抛出,它不能是
myex
,因为堆栈(可能)被解开了。@SamJ:这不是一个问题,这是一个语句,它与这种情况无关,因为你没有调用函数。@SamJ:很抱歉让我的答案无人参与,但其他人已经用我的话回答了你的问题。不,我不依赖任何输出来确定答案,这只是它的工作方式。你说
扔x,编译器复制
x
,然后找到它应该跳转到的位置进行捕获。我理解这一点,但我的问题与你的答案完全不同。在上面的程序中,您可以看到正在调用复制构造函数(如果您编写了一个复制构造函数,那么您就可以看到它),这将生成一个单独的obj副本。但实际上复制构造函数仅对临时对象(如按值传递)调用。@SamJ:但实际上复制构造函数仅对临时对象(如按值传递)调用。这是一个很好的陈述,也是一个错误。可以为临时对象以外的其他对象创建副本,在某些情况下,临时对象既不是副本的结果,也不会复制自身。
#include <iostream>
#include <exception>
using namespace std;


class myexception: public exception
{
  virtual const char* what() const throw()
  {
    return "My exception happened";
  }
};

int main ()
{
  try
  {
    myexception myex;
    printf("addr1:%x\n",&myex);
    throw myex;
  }
  catch (exception& e)
  {
    printf("addr2:%x\n",&e);
    cout << e.what() << endl;
  }
  return 0;
}
addr1:6d78c020
addr2:20a1080
My exception happened