尝试并捕获C++ - 创建了多少对象
try and catch in C++ - how many objects are created
请考虑以下代码:
#include <iostream>
#include <string>
class Box{
public:
std::string show(){
std::cout<<"Box show executed"<<std::endl;
return "msg";
};
~Box(){
std::cout<<"Box destructor is executed"<<std::endl;
};
};
int main(){
try{
Box obj;
std::cout<<"Coming here"<<std::endl;
throw obj;
}
catch(Box msg){
std::cout<<"I have caught the exception: n"<<msg.show()<<std::endl;
}
}
在 GCC 编译器中,输出为:
Coming here
Box destructor is executed
Box show executed
I have caught the exception:
msg
Box destructor is executed
Box destructor is executed
我的困惑是:
声明印刷品很混乱,为什么"盒子秀"是 在"我已捕获异常"行之前执行"打印?
有三个析构函数称为,当只有 创建两个对象,一个是 try 中的 Box 对象,另一个是 temp 对象 尝试中的对象被传递给 catch 块?
语句打印非常混乱,为什么"Box show 已执行"打印在"我已捕获异常"行之前?
未指定函数/运算符参数的计算顺序。您的代码等效于以下内容:
operator<<(operator<<((std::cout << "I have caught the exception: n"), msg.show()), std::endl);
以下两个中哪一个先执行是未定义的:
std::cout << "I have caught the exception: n"
msg.show() // i.e. std::cout << "Box show executed" << std::endl;
在您的情况下,msg.show()
在调用第一个operator <<
之前进行评估。不同的编译器可能会以不同的顺序生成具有这些调用的代码。
有三个析构函数称为,当只创建两个对象时,这怎么可能,一个是 try 中的 Box 对象,另一个是传递给 catch 块的 try 中的临时对象?
按值抛出本地对象时:
- 它被复制到一个特殊的保留内存中,以备异常使用。
- 原始对象被销毁 (1(。
- 应找到异常处理程序,并将对象从特殊的保留内存复制到异常处理程序堆栈。
- 复制的对象将从特殊存储器 (2( 中删除。
- 当异常处理程序退出时,对象将从其堆栈 (3( 中删除。
为什么在"我抓住了 例外"行?
因为它想在catch
部分中计算show()
方法,所以它将首先打印字符串。
有三个析构函数称为
因为您正常捕获Box
,所以如果您使用Box&
,您将只看到 2 次对析构函数的调用。在您的代码中,对象被复制两次,对于 1 个主对象,您需要 3 次析构函数调用。如果按如下所示更改代码,则会看到这些复制构造函数:
#include <iostream>
#include <string>
class Box{
public:
Box(){}
Box(const Box &obj){
std::cout <<"copy"<<std::endl;
}
std::string show(){
std::cout<<"Box show executed"<<std::endl;
return "msg";
};
~Box(){
std::cout<<"Box destructor is executed"<<std::endl;
};
};
int main(){
try{
Box obj;
std::cout<<"Coming here"<<std::endl;
throw obj;
}
catch(Box msg){
std::cout<<"I have caught the exception: n"<<msg.show()<<std::endl;
}
}
结果将是:
Coming here
copy // <-- for throw
Box destructor is executed
copy // <-- when you catch at catch(Box msg)
Box show executed
I have caught the exception:
msg
Box destructor is executed
Box destructor is executed
这些copy
是干什么用的?一个是给throw obj;
的,一个是给catch(Box msg)
的。
我认为如果您将构造函数和复制构造函数添加到代码中,这将有助于您了解正在发生的事情。
#include <iostream>
#include <string>
class Box {
public:
std::string show() {
std::cout << "Box show executed - " << this << std::endl;
return "msg";
};
Box() {
std::cout << "Box constructor is executed " << this << std::endl;
}
Box(const Box& rhs) {
std::cout << "Box copy constructor is executed " << this << std::endl;
}
~Box() {
std::cout << "Box destructor is executed " << this << std::endl;
};
};
int main() {
try {
Box obj;
std::cout << "Coming here" << std::endl;
throw obj;
}
catch (Box msg) {
std::cout << "I have caught the exception: n" << msg.show() << std::endl;
}
}
这将生成以下输出:
/*
Box constructor is executed 0051FB0B
Coming here
Box copy constructor is executed 0051FA33
Box copy constructor is executed 0051FAFF
Box destructor is executed 0051FB0B
Box show executed - 0051FAFF
I have caught the exception: msg
Box destructor is executed 0051FAFF
Box destructor is executed 0051FA33
*/
所以你可以看到#1的答案是在投掷和接球期间创建了两个新对象。紧接着,原始对象将被销毁,因为它现在超出了其块范围。
下一部分有点令人困惑,因为有两个嵌套的 std::cout 语句。在这种情况下,编译器选择在生成行的第一部分"我已捕获异常..."的输出之前完全解析表达式 msg.show((。因此,在解析 msg.show(( 的值时,msg.show(( 首先生成了自己的输出行"Box show ....."这就是为什么它排在第一位。正如 S.M. 在他的回答中指出的那样,编译器选择计算嵌套 std::cout 的顺序是实现定义的,并且不能保证这种操作顺序。
最后,在 catch 中创建的对象被销毁,然后从 try 创建的对象被销毁。
- 如何创建一个所有行大小不同的 2D 数组,并且用户将指定每行将有多少个元素?
- 如何查看在程序级别为我的程序创建了多少 vtable 和 vpointer
- 如何创建一个递归函数来显示有多少元音具有输入
- 使用 CommonAPI 编写服务器时C++服务器进程中创建了多少个线程?
- 尝试并捕获C++ - 创建了多少对象
- 在运行时创建 DFA.多少个州
- 尝试创建一个读取.txt文件,显示它,计数唯一单词的程序,并在使用了多少次的情况下显示独特的单词.C
- 在没有返回值优化的情况下将两个对象加在一起时,将创建多少个临时对象
- STD :: async的最大线程数量是多少,将异步创建和执行
- 假设没有编译器优化,则将创建多少次此对象
- 使用 fork() 在此代码中创建多少个进程
- 创建多个实例后,静态数据成员的值是多少
- 将创建多少个对象
- 我应该为IOCP创建多少个线程
- 当我从内联函数返回字符串时,会创建多少个临时对象
- 我应该创建多少个线程
- 一个C++应用程序可以创建多少个线程
- 初级C++:在不知道要创建多少对象的情况下在运行时创建对象
- 下面的代码将创建多少个V表
- 在此示例中将创建多少个 vtable 和 vpointer