In C++, when is an object defined as "out of scope"?
在C ++中,何时将对象定义为“超出范围”?
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?
更具体地说,如果我有一个单链表,那么将单个列表节点对象定义为“超出范围”?或者,如果一个对象存在并且被变量ptr引用,那么在删除引用或指向另一个对象时,该对象被定义为“超出范围”是否正确?
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:
换句话说,list_1指向的Node是否会在此行之后调用其析构函数:
Node* list_1 = new Node (3);
?
5 个解决方案
#1
41
First, remember that objects in C++ can be created either on the stack or on on the heap.
首先,请记住,可以在堆栈上或堆上创建C ++中的对象。
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.
堆栈框架(或范围)由语句定义。这可以像函数一样大或者像流控制块一样小(而/ if / for等)。包含任意代码块的任意{}对也构成堆栈帧。一旦程序退出该帧,框架内定义的任何局部变量都将超出范围。当堆栈变量超出范围时,将调用其析构函数。
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语句的主体:
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.
在堆上声明的对象在一种方式之后在堆栈帧之间“存活”。可以说,在堆上声明的对象永远不会超出范围,但这确实是因为该对象永远不会与任何范围真正关联。必须通过new关键字创建这样的对象,并且必须通过指针引用。
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.
一旦完成堆对象,您有责任释放堆对象。您可以使用delete关键字释放堆对象。在释放对象之前,不会调用堆对象上的析构函数。
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
#2
5
{ //scope is defined by the curly braces
std::vector<int> vec;
}
// vec is out of scope here!
vec.push_back(15);
#3
2
"Out of scope" is a metonymy: as in, using the name or terminology of one concept to talk about something closely related but different.
“超出范围”是一种转喻:如同使用一个概念的名称或术语来谈论密切相关但又不同的东西。
In C++ a scope is a static region of program text, and so something "out of scope", taken literally, means physically outside of a region of text. For instance, { int x; } int y;
: the declaration of y
is out of the scope in which x
is visible.
在C ++中,范围是程序文本的静态区域,因此字面意义上的“超出范围”意味着在文本区域之外。例如,{int x; } int y ;: y的声明超出了x可见的范围。
The metonymy "going out of scope" is used to express the idea that the dynamic activation/instantiation of the environment associated with some scope is terminating. And so the variables defined in that scope are going away (thus "out of scope").
转喻“超出范围”用于表示与某个范围相关联的环境的动态激活/实例化正在终止的想法。因此,该范围中定义的变量将消失(因此“超出范围”)。
What has actually gone "out of scope" is the instruction pointer, so to speak; the program's evaluation is now taking place in a scope which has no visibility to that one. But not everything in a scope goes away! Static variables will still be there the next time the scope is entered.
实际上“超出范围”的是指令指针,可以这么说;该计划的评估现在正在一个范围内进行,该范围对该视图没有可见性。但并非范围内的所有内容都消失了!下次输入范围时,静态变量仍然存在。
"Going out of scope" is not very accurate, but short and everyone understands what it means.
“超出范围”不是很准确,但很短,每个人都明白这意味着什么。
#4
2
An object that is declared inside a function (or inside certain curly-brace-bracketed constructs inside functions) falls out of scope when execution leaves that part of code.
在执行离开该部分代码时,在函数内部声明的对象(或函数内部的某些花括号括号内的构造内部)会超出范围。
void some_func() {
std::string x("Hello!");
// x is in scope here
}
// But as soon as some_func returns, x is out of scope
This only applies to stuff declared on the stack, so it has little to do with singly-linked lists, since list nodes will typically be instantiated on the heap with new
.
这仅适用于在堆栈上声明的内容,因此它与单链接列表几乎没有关系,因为列表节点通常会在堆上用new实例化。
In this example, the pointer returned by new
will go out of scope when the function exits, but nothing will happen to the Node itself:
在这个例子中,当函数退出时,new返回的指针将超出范围,但Node本身不会发生任何事情:
void make_a_node() {
Node* p = new Node;
} // Oh noes a memory leak!
#5
1
When it leaves the scope that it was declared in :)
当它离开声明它的范围:)
Your question as it stands is not answerable without seeing the implementation. It comes down to where you declare this node.
如果没有看到实施,你现在的问题是无法回答的。它归结为您声明此节点的位置。
void Foo()
{
int i = 10;
{
int j = 20;
} // j is out of scope
} // i is out of scope
#1
41
First, remember that objects in C++ can be created either on the stack or on on the heap.
首先,请记住,可以在堆栈上或堆上创建C ++中的对象。
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.
堆栈框架(或范围)由语句定义。这可以像函数一样大或者像流控制块一样小(而/ if / for等)。包含任意代码块的任意{}对也构成堆栈帧。一旦程序退出该帧,框架内定义的任何局部变量都将超出范围。当堆栈变量超出范围时,将调用其析构函数。
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语句的主体:
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.
在堆上声明的对象在一种方式之后在堆栈帧之间“存活”。可以说,在堆上声明的对象永远不会超出范围,但这确实是因为该对象永远不会与任何范围真正关联。必须通过new关键字创建这样的对象,并且必须通过指针引用。
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.
一旦完成堆对象,您有责任释放堆对象。您可以使用delete关键字释放堆对象。在释放对象之前,不会调用堆对象上的析构函数。
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
#2
5
{ //scope is defined by the curly braces
std::vector<int> vec;
}
// vec is out of scope here!
vec.push_back(15);
#3
2
"Out of scope" is a metonymy: as in, using the name or terminology of one concept to talk about something closely related but different.
“超出范围”是一种转喻:如同使用一个概念的名称或术语来谈论密切相关但又不同的东西。
In C++ a scope is a static region of program text, and so something "out of scope", taken literally, means physically outside of a region of text. For instance, { int x; } int y;
: the declaration of y
is out of the scope in which x
is visible.
在C ++中,范围是程序文本的静态区域,因此字面意义上的“超出范围”意味着在文本区域之外。例如,{int x; } int y ;: y的声明超出了x可见的范围。
The metonymy "going out of scope" is used to express the idea that the dynamic activation/instantiation of the environment associated with some scope is terminating. And so the variables defined in that scope are going away (thus "out of scope").
转喻“超出范围”用于表示与某个范围相关联的环境的动态激活/实例化正在终止的想法。因此,该范围中定义的变量将消失(因此“超出范围”)。
What has actually gone "out of scope" is the instruction pointer, so to speak; the program's evaluation is now taking place in a scope which has no visibility to that one. But not everything in a scope goes away! Static variables will still be there the next time the scope is entered.
实际上“超出范围”的是指令指针,可以这么说;该计划的评估现在正在一个范围内进行,该范围对该视图没有可见性。但并非范围内的所有内容都消失了!下次输入范围时,静态变量仍然存在。
"Going out of scope" is not very accurate, but short and everyone understands what it means.
“超出范围”不是很准确,但很短,每个人都明白这意味着什么。
#4
2
An object that is declared inside a function (or inside certain curly-brace-bracketed constructs inside functions) falls out of scope when execution leaves that part of code.
在执行离开该部分代码时,在函数内部声明的对象(或函数内部的某些花括号括号内的构造内部)会超出范围。
void some_func() {
std::string x("Hello!");
// x is in scope here
}
// But as soon as some_func returns, x is out of scope
This only applies to stuff declared on the stack, so it has little to do with singly-linked lists, since list nodes will typically be instantiated on the heap with new
.
这仅适用于在堆栈上声明的内容,因此它与单链接列表几乎没有关系,因为列表节点通常会在堆上用new实例化。
In this example, the pointer returned by new
will go out of scope when the function exits, but nothing will happen to the Node itself:
在这个例子中,当函数退出时,new返回的指针将超出范围,但Node本身不会发生任何事情:
void make_a_node() {
Node* p = new Node;
} // Oh noes a memory leak!
#5
1
When it leaves the scope that it was declared in :)
当它离开声明它的范围:)
Your question as it stands is not answerable without seeing the implementation. It comes down to where you declare this node.
如果没有看到实施,你现在的问题是无法回答的。它归结为您声明此节点的位置。
void Foo()
{
int i = 10;
{
int j = 20;
} // j is out of scope
} // i is out of scope