对象内存模型的有关问题: 对象数组的构造过程如果失败了,被构造的对象会被析构么
对象内存模型的问题: 对象数组的构造过程如果失败了,被构造的对象会被析构么?
<<深入理解C++对象内存模型>>这本书上对于对象数组的构造是这样解释的,编译器会把ctor/dtor的地址都push到堆栈上,作为一个编译器生成的函数参数:
object *pobj=new object[some];会让编译器产生一个函数:
因此object *pobj=new object[some];语句就被编译成了两个调用:
之所以要传入dtor的地址,是为了当ctor循环没有完全成功的时候,例如构造了若干个以后遇到了异常,那么就终止构造并析构已经构造了的对象门。
-------------------问题---------------------
我试验了一下,似乎没有什么事情能使得,当某次执行构造函数失败的时候,编译器自动生成的代码能帮我析构已经构造的那些个对象。下面的小程序是这样的: 构造函数计算i,当s_count=5的时候,遇到除0错误,抛出异常。这个异常并不能触发对象的析构函数。
我不知道编译器为objectArrayCtor传入dtor的地址到底有什么用,怎么样才能触发这个dtor呢?
------解决方案--------------------
标准保证 stack unwinding 过程中,已构造的数组对象按逆序析够。主楼的程序导致 uncaught exception,因此没有发生 stack unwinding,因此没有析够,改成下面这样就能看到效果了。
<<深入理解C++对象内存模型>>这本书上对于对象数组的构造是这样解释的,编译器会把ctor/dtor的地址都push到堆栈上,作为一个编译器生成的函数参数:
object *pobj=new object[some];会让编译器产生一个函数:
- C/C++ code
void objectArrayCtor( (void)(*pCtor)(), (void)(*pDtor), object* pMem, size_t nCount ){ try{ for(int c=0;c<nCount;++c){ pMem[c]->object::object();//构造函数调用 } }... }
因此object *pobj=new object[some];语句就被编译成了两个调用:
- C/C++ code
object *pobj=operator new(some* sizeof(object)); objectArrayCtor( &object::object, &object::~object, pobj, some);
之所以要传入dtor的地址,是为了当ctor循环没有完全成功的时候,例如构造了若干个以后遇到了异常,那么就终止构造并析构已经构造了的对象门。
-------------------问题---------------------
我试验了一下,似乎没有什么事情能使得,当某次执行构造函数失败的时候,编译器自动生成的代码能帮我析构已经构造的那些个对象。下面的小程序是这样的: 构造函数计算i,当s_count=5的时候,遇到除0错误,抛出异常。这个异常并不能触发对象的析构函数。
我不知道编译器为objectArrayCtor传入dtor的地址到底有什么用,怎么样才能触发这个dtor呢?
- C/C++ code
#include<stdexcept> using namespace std; struct s{ static int s_count; int i; s() { ++s_count; printf("ctor %d,%p\n",s_count,this); try{ if(s_count==5)throw std::range_error("divide 0!"); i=10/(s_count-5); //divide by 0 when s_count=5 } catch(exception& e){ throw e; } } ~s() { printf("dtor %p\n",this); } }; int s::s_count=0; int main(int,char*[]){ s* ps=new s[10]; delete[]ps; return 0; }
------解决方案--------------------
标准保证 stack unwinding 过程中,已构造的数组对象按逆序析够。主楼的程序导致 uncaught exception,因此没有发生 stack unwinding,因此没有析够,改成下面这样就能看到效果了。
- C/C++ code
#include<stdexcept> using namespace std; struct s{ static int s_count; int i; s() { ++s_count; printf("ctor %d,%p\n",s_count,this); try{ if(s_count==5)throw std::range_error("divide 0!"); i=10/(s_count-5); //divide by 0 when s_count=5 } catch(exception& e){ throw e; } } ~s() { printf("dtor %p\n",this); } }; int s::s_count=0; int main(int,char*[]){ try { s* ps=new s[10]; delete[]ps; } catch (...) // stack unwinding happened before this point. { } return 0; }