C++没构造却有析构

C++没有构造却有析构
代码:
Exception.h

#include <iostream>
#include <string>
using namespace std;
class Exception
{
public:
Exception();
~Exception();
string getMsg();
void setMsg(string msg);
private:
string msg;
};

Exception.cpp

#include "Exception.h"

Exception::Exception()
{
cout << "constructed" << endl;
}

Exception::~Exception()
{
cout << "deconstructed" << endl;
}

string Exception::getMsg()
{
return this->msg;
}

void Exception::setMsg(string msg)
{
this->msg = msg;
}

Main.cpp

#include "Exception.h"

void test()
{
Exception e;
e.setMsg("error");
throw e;
}

int main()
{
try
{
test();
}
catch (Exception e)
{
cout << e.getMsg() << endl;
}
catch (...)
{
cout << "unknow" << endl;
}
return 0;
}


运行结果:
constructed
deconstructed
error
deconstructed
deconstructed

问题:
刚开始抛出异常是使用的指针的方式没有问题,后来就想用对象的方式试一下,结果出现的结果,想不明白。没有调用构造方法,却调用了析构方法,居然还调用了两次析构方法,实在是想不懂为什么会出现这种情况,就上来求助了。

我还使用Qt测试一下,新建项目是qt项目,Exception类继承了QObject类,发现这种方式throw这个Exception对象的话,就会出现####QObject::QObject: 无法访问 private 成员(在QObject类中声明)####的错误,如果这个Exception对象是指针的话就没有问题。
没有构造却有析构 c++

------解决方案--------------------
3楼正解了~ 

我大概说下三楼的意思  

throw e;会调用拷贝构造函数复制你要throw的对象
catch(Exception e)也会调用拷贝构造函数复制你throw过来的对象
这就会有两次调用 
而当catch这句复制完对象后 throw e;这句产生的副本就会被释放掉 从而有析构函数的调用
往后就不难理解了~
------解决方案--------------------
LZ问构造函数与拷贝函数的区别?
我来解答一下吧,拷贝构造函数也是构造函数的一种,因为构造函数值支持重载的。
但是拷贝构造函数的参数只能有一个,那就是本类对象
Exception(Exception e);也就是说根据给定的一个对象来复制出一个一模一样的出来对象出来。
一般会在自定义类对象的传参,函数返回自定义类对象时候会调用拷贝构造函数
------解决方案--------------------
引用:
我看了这个网站的文章
http://baiy.cn/doc/cpp/inside_exception.htm
《C++异常机制的实现方式和开销分析》
可能我有点笨,愣是没有看懂~


此文和你的疑问应该不对题

你与#9楼各说各话,因为编译器不同

事情A:catch (Exception e) 这里的拷贝构造
事情B:栈回退

VC的方式:事情A先于事情B
GCC的方式:事情B先于事情A

我在#10楼说了,我不知道VC的做法是否违背C++标准,如果没有,则这只是实现上的灵活性
------解决方案--------------------
引用:
“catch (Exception e)这里又拷贝构造一次”这里是在退出test作用域调用的吗?
你看一下运行结果:
constructed 0
copy constructed 1
copy constructed 2
deconstructed 0
test函数作用域结束之前以前再一次的调用了拷贝构造函数了 

你在析构函数下个端点不就知道,这个析构函数是啥时候调用的么
在throw之后,已经退出test函数的作用域了。
e的析构是由异常处理调用的。



第一次拷贝构造的,调用栈。可以明确地时候看到是test调用的
C++没构造却有析构
第二次拷贝构造,可以明确地看到 不是test调用的
C++没构造却有析构
第一次析构,明确地看到是异常处理调用的。
C++没构造却有析构
第二次拷贝构造之前已经离开了test的作用域了。