Pat*_*ray 26 c++ destructor scope
在C++中,何时将对象定义为"超出范围"?
更具体地说,如果我有一个单链表,那么将单个列表节点对象定义为"超出范围"?或者,如果一个对象存在并且被一个变量引用ptr,那么在删除引用或指向另一个对象时,该对象被定义为"超出范围"是否正确?
更新:假设一个对象是一个具有已实现的析构函数的类.在对象退出范围的那一刻,是否会调用析构函数?
if (myCondition) {
Node* list_1 = new Node (3);
Node* list_2 = new Node (4);
Node* list_3 = new Node (5);
list_1->next = list_2;
list_2->next = list_3;
list_3->next = null;
}
Run Code Online (Sandbox Code Playgroud)
换句话说,通过list_1在此行之后调用其析构函数来指向Node :
Node* list_1 = new Node (3);
Run Code Online (Sandbox Code Playgroud)
?
spa*_*ead 49
首先,请记住,可以在堆栈上或堆上创建C++中的对象.
堆栈框架(或范围)由语句定义.这可以像函数一样大,也可以像流控制块一样小(while/ if/ for等).{}包含任意代码块的任意对也构成堆栈帧.一旦程序退出该帧,框架内定义的任何局部变量都将超出范围.当堆栈变量超出范围时,将调用其析构函数.
所以这里是一个堆栈帧(函数的执行)和在其中声明的局部变量的经典示例,一旦堆栈帧退出,它将超出范围 - 一旦函数完成:
void bigSideEffectGuy () {
BigHeavyObject b (200);
b.doSomeBigHeavyStuff();
}
bigSideEffectGuy();
// a BigHeavyObject called b was created during the call,
// and it went out of scope after the call finished.
// The destructor ~BigHeavyObject() was called when that happened.
Run Code Online (Sandbox Code Playgroud)
这是一个示例,我们看到堆栈框架只是一个if语句的主体:
if (myCondition) {
Circle c (20);
c.draw();
}
// c is now out of scope
// The destructor ~Circle() has been called
Run Code Online (Sandbox Code Playgroud)
在退出帧之后,堆栈创建的对象"保持在范围内"的唯一方法是它是否是函数的返回值.但这并不是真的"留在范围内",因为对象正在被复制.因此原件超出了范围,但是制作了副本.例:
Circle myFunc () {
Circle c (20);
return c;
}
// The original c went out of scope.
// But, the object was copied back to another
// scope (the previous stack frame) as a return value.
// No destructor was called.
Run Code Online (Sandbox Code Playgroud)
现在,也可以在堆上声明一个对象.为了便于讨论,将堆视为无限的内存块.与堆栈不同,堆栈在您进入和退出堆栈帧时自动分配和取消分配必要的内存,您必须手动保留并释放堆内存.
在堆上声明的对象在一种方式之后在堆栈帧之间"存活".可以说在堆上声明的对象永远不会超出范围,但这确实是因为该对象永远不会与任何范围真正关联.必须通过new关键字创建这样的对象,并且必须通过指针引用.
一旦完成堆对象,您有责任释放堆对象.您可以使用delete关键字释放堆对象.在释放对象之前,不会调用堆对象上的析构函数.
引用堆对象的指针本身通常是与作用域相关的局部变量.一旦完成使用堆对象,就允许引用它的指针超出范围.如果您没有显式释放指针所指向的对象,则在进程退出之前永远不会释放堆内存块(这称为内存泄漏).
一想到这一点:在堆栈上创建的对象就像是绑在房间里的椅子上的气球.退出房间时,气球会自动弹出.在堆上创建的对象就像是在功能区上的气球,系在房间的椅子上.功能区是指针.当您离开房间时,色带会自动消失,但气球只会漂浮在天花板上并占据空间.正确的程序是用针弹出气球,然后退出房间,然后色带将消失.但是,关于绳子上的气球的好处是你也可以解开色带,把它拿在手里,然后离开房间,带上气球.
因此,转到链接列表示例:通常,此类列表的节点在堆上声明,每个节点都包含指向下一个节点的指针.所有这一切都坐在堆上,永远不会超出范围.唯一可能超出范围的是指向列表根目录的指针 - 用于首先引用到列表中的指针.这可能超出范围.
这是一个在堆上创建东西,并且根指针超出范围的示例:
if (myCondition) {
Node* list_1 = new Node (3);
Node* list_2 = new Node (4);
Node* list_3 = new Node (5);
list_1->next = list_2;
list_2->next = list_3;
list_3->next = null;
}
// The list still exists
// However list_1 just went out of scope
// So the list is "marooned" as a memory leak
Run Code Online (Sandbox Code Playgroud)
{ //scope is defined by the curly braces
std::vector<int> vec;
}
// vec is out of scope here!
vec.push_back(15);
Run Code Online (Sandbox Code Playgroud)