什么时候是一个对象“超出范围”? [英] When is an object "out of scope"?

查看:130
本文介绍了什么时候是一个对象“超出范围”?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C ++中,when是一个定义为超出范围的对象?



更具体地说,如果我有一个单链表,什么会将单个列表节点对象定义为超出范围?或者如果一个对象存在并且正在被一个变量'ptr'引用,在引用被删除或者指向一个不同对象的时刻,该对象是否被定义为超出范围是正确的?



UPDATE:假设一个对象是一个实现了析构函数的类。

  if(myCondition){
Node * list_1 =新节点(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;
}

换句话说,list_1指向的节点将调用它的析构函数这行:



Node * list_1 = new Node(3);



解决方案

首先,记住C ++中的对象可以



堆栈框架(或作用域)由堆栈框架一份声明。这可以像一个函数那样大或者像一个流控制块一样小( while / if / for 等)。包含任意代码块的任意 {} 对也构成一个堆栈帧。一个框架内定义的任何局部变量将超出范围,一旦程序退出该框架。当一个栈变量超出范围,它的析构函数被调用。



这里是一个栈框架(一个函数的执行)和一个在其中声明的局部变量的典型示例,它将在堆栈框架退出 - 一旦函数完成:

  void bigSideEffectGuy(){
BigHeavyObject b
b.doSomeBigHeavyStuff();
}
bigSideEffectGuy();
//在调用期间创建了一个名为b的BigHeavyObject,
//并且在调用完成后它超出范围。
//析构函数〜BigHeavyObject()被调用时发生。

这里有一个例子,我们看到一个堆栈框架只是一个 if(myCondition){
Circle c(20); if if(myCondition){
Circle c(20); if <
c.draw();
}
// c现在超出范围
//析构函数〜Circle()已被调用

在框架退出之后,堆栈创建的对象保持在作用域中的唯一方法是如果它是一个函数的返回值。但这不是真正的保持在范围,因为对象被复制。所以原来超出范围,但一个副本。示例:

  Circle myFunc(){
Circle c(20);
return c;
}
//原来的c超出范围。
//但是,对象被复制回另一个
//范围(前一个堆栈帧)作为返回值。
//没有析构函数被调用。

现在,一个对象也可以在堆上声明。为了这个讨论,把堆看成是一个无定形的记忆。与堆栈不同,堆栈在进入和退出堆栈帧时自动分配和取消分配必要的内存,您必须手动预留和释放堆内存。



在堆上声明的对象在时间之后在堆栈帧之间存活。可以说,在堆上声明的对象永远不会超出范围,但这真的是因为对象从不真正与任何范围相关联。这样的对象必须通过 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;
}
//列表仍然存在
//但是list_1刚刚超出范围
//所以列表是marooned作为内存泄漏


In C++, when is an object defined as "out of scope"?

More specifically, if I had a singly linked list, what would define a single list node object as "out of scope"? Or if an object exists and is being referenced by a variable 'ptr', is it correct to say that the object is defined as "out of scope" the moment the reference is deleted or points to a different object?

UPDATE: Assuming an object is a class that has an implemented destructor. Will the destructor be called the moment the object exits the scope?

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;
}

In other words, would the Node being pointed to by list_1 call its destructor after this line:

Node* list_1 = new Node (3);

?

解决方案

First, remember that objects in C++ can be created either on the stack or on on the heap.

A stack frame (or scope) is defined by a statement. That can be as big as a function or as small as a flow control block (while/if/for etc.). An arbitrary {} pair enclosing an arbitrary block of code also constitutes a stack frame. Any local variable defined within a frame will go out of scope once the program exits that frame. When a stack variable goes out of scope, its destructor is called.

So here is a classic example of a stack frame (an execution of a function) and a local variable declared within it, which will go out of scope once the stack frame exits - once the function finishes:

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.

Here is an example where we see a stack frame being just the body of an if statement:

if (myCondition) {
    Circle c (20);
    c.draw();
}
// c is now out of scope
// The destructor ~Circle() has been called

The only way for a stack-created object to "remain in scope" after the frame is exited is if it is the return value of a function. But that is not really "remaining in scope" because the object is being copied. So the original goes out of scope, but a copy is made. Example:

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.

Now, an object can also be declared on the heap. For the sake of this discussion, think of the heap as an amorphous blob of memory. Unlike the stack, which automatically allocates and de-allocates the necessary memory as you enter and exit stack frames, you must manually reserve and free heap memory.

An object declared on the heap does, after a fashion, "survive" between stack frames. One could say that an object declared on the heap never goes out of scope, but that's really because the object is never really associated with any scope. Such an object must be created via the new keyword, and must be referred to by a pointer.

It is your responsibility to free the heap object once you are done with it. You free heap objects with the delete keyword. The destructor on a heap object is not called until you free the object.

The pointers that refer to heap objects are themselves usually local variables associated with scopes. Once you are done using the heap object, you allow the pointer(s) referring to it to go out of scope. If you haven't explicitly freed the object the pointer is pointing to, then the block of heap memory will never be freed until the process exits (this is called a memory leak).

Think of it all this way: an object created on the stack is like a balloon taped to a chair in a room. When you exit the room, the balloon automatically pops. An object created on the heap is like a balloon on a ribbon, tied to a chair in a room. The ribbon is the pointer. When you exit the room, the ribbon automatically vanishes, but the balloon just floats to the ceiling and takes up space. The proper procedure is to pop the balloon with a pin, and then exit the room, whereupon the ribbon will disappear. But, the good thing about the balloon on the string is you can also untie the ribbon, hold it in your hand, and exit the room and take the balloon with you.

So to go to your linked list example: typically, nodes of such a list are declared on the heap, with each node holding a pointer to the next node. All of this is sitting on the heap and never goes out of scope. The only thing that could go out of scope is the pointer that points to the root of the list - the pointer you use to reference into the list in the first place. That can go out of scope.

Here's an example of creating stuff on the heap, and the root pointer going out of scope:

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

这篇关于什么时候是一个对象“超出范围”?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆