More Effective C++ 读书笔记五——异常-阿里云开发者社区

开发者社区> 开发与运维> 正文

More Effective C++ 读书笔记五——异常

简介: 条款12:了解“抛出一个exception”与“传递一个参数”或“调用一个虚函数”之间的差异 第一,exception object总是会被复制,如果以by value方式捕捉,它们甚至被复制两次。至于传递给函数参数的对象不一定得复制。第二,“被抛出成为exceptions”的对象,其被允许的

条款12:了解“抛出一个exception”与“传递一个参数”或“调用一个虚函数”之间的差异

第一,exception object总是会被复制,如果以by value方式捕捉,它们甚至被复制两次。至于传递给函数参数的对象不一定得复制。第二,“被抛出成为exceptions”的对象,其被允许的类型转换动作,比“被传递到函数去”的对象少。第三,catch子句以其“出现于源代码的顺序”被编译器检查比对,其中第一个匹配成功者便被执行;而当我们以某个对象调用一个虚函数,被选中执行的是那个“与对象类型最佳吻合”的函数。

条款13:以by reference方式捕捉exceptions

上面两个条款都提到了被抛出对象的复制问题,通过下面的几个例子试了下:
[cce lang=”cpp”]
#include <iostream>

static int count = 0;

class e_class {
public:
e_class() {
std::cout << “in constructor: count: ” << ++count << std::endl;
}
e_class(const e_class &right) {
std::cout << “in copy constructor: count: ” << ++count << std::endl;
}
};

int main(){
try {
e_class e_c; //创建对象,调用构造函数count累加
throw e_c; //抛出异常,e_c被复制,调用拷贝构造函数,count累加
} catch (e_class e) { //以by value形式catch,对象再次被复制,count累加
}

return 0;
}
[/cce]
这里count被加了3次,第一次是e_class对象构造的时候,然后抛出去的时候,对象被复制,然后catch的时候因为按值传递,传入对象再次被复制。执行结果为:
in constructor: count: 1
in copy constructor: count: 2
in copy constructor: count: 3
这里能被避免的就是catch这里,如果按照引用传递,这次复制就可以避免:
[cce lang=”cpp”]
#include <iostream>

static int count = 0;

class e_class {
public:
e_class() {
std::cout << “in constructor: count: ” << ++count << std::endl;
}
e_class(const e_class &right) {
std::cout << “in copy constructor: count: ” << ++count << std::endl;
}
};

int main(){
try {
e_class e_c; //创建对象,调用构造函数count累加
throw e_c; //抛出异常,e_c被复制,调用拷贝构造函数,count累加
} catch (e_class &e) { //以by reference形式catch,不会再次被复制
}

return 0;
}
[/cce]
采用按引用方式catch后,和函数按引用传递参数一样,对象不再被复制,执行结果为:
in constructor: count: 1
in copy constructor: count: 2

条款12中还介绍了再次抛出异常的对象复制问题:
[cce lang=”cpp”]
#include <iostream>

static int count = 0;

class e_class {
public:
e_class() {
std::cout << “in constructor: count: ” << ++count << std::endl;
}
e_class(const e_class &right) {
std::cout << “in copy constructor: count: ” << ++count << std::endl;
}
};

int main(){
try {
try {
e_class e_c;
throw e_c;
} catch (e_class &e) {
throw e; //这里抛出的是e的副本,会对e进行复制后抛出
}
}catch(…) {
}

return 0;
}
[/cce]
这里在catch子句中重新抛出了异常,但是这种方式抛出的其实是异常对象的副本,对象会再次被复制,执行结果为:
in constructor: count: 1
in copy constructor: count: 2
in copy constructor: count: 3
如果改成这样:
[cce lang=”cpp”]
#include <iostream>

static int count = 0;

class e_class {
public:
e_class() {
std::cout << “in constructor: count: ” << ++count << std::endl;
}
e_class(const e_class &right) {
std::cout << “in copy constructor: count: ” << ++count << std::endl;
}
};

int main(){
try {
try {
e_class e_c;
throw e_c;
} catch (e_class &e) {
throw; //直接抛出e,不会进行复制
}
}catch(…) {
}

return 0;
}
[/cce]
这里throw语句不带任何参数,抛出的是当前异常本身,当前的异常对象不会再次被复制,执行结果为:
in constructor: count: 1
in copy constructor: count: 2


转载自:https://coolex.info/blog/267.html

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章