什么时候是对象;超出范围;? 在C++中,什么时候定义一个对象为“超出范围”?

什么时候是对象;超出范围;? 在C++中,什么时候定义一个对象为“超出范围”?,c++,scope,destructor,C++,Scope,Destructor,更具体地说,如果我有一个单链表,那么如何将单个列表节点对象定义为“超出范围”?或者,如果存在一个对象,并且该对象正被一个变量ptr引用,那么在引用被删除或指向另一个对象时,该对象被定义为“超出范围”是否正确 更新:假设对象是具有已实现析构函数的类。当对象退出作用域时,是否会调用析构函数 if (myCondition) { Node* list_1 = new Node (3); Node* list_2 = new Node (4); Node* list_3 = ne

更具体地说,如果我有一个单链表,那么如何将单个列表节点对象定义为“超出范围”?或者,如果存在一个对象,并且该对象正被一个变量
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;
}
换句话说,
list_1
指向的节点会在这一行之后调用其析构函数吗:

Node* list_1 = new Node (3);

{//范围由大括号定义
std::vec;
}
//vec超出了范围!
向量推回(15);

当它离开声明它的范围时:)

你的问题在没有看到实施的情况下是无法回答的。这取决于您在何处声明此节点

void Foo()
{
    int i = 10;

    {
        int j = 20;
    } // j is out of scope

} // i is out of scope
“超出范围”是一种转喻:例如,使用一个概念的名称或术语来谈论密切相关但不同的事物

在C++中,范围是程序文本的静态区域,所以字面上的“超出范围”的东西在物理上意味着在文本区域之外。例如,
{intx;}inty
y
的声明超出了
x
可见的范围

转喻“走出范围”是用来表达与某个范围相关的环境的动态激活/实例化正在终止的想法。因此,在该范围内定义的变量正在消失(因此“超出范围”)

可以说,真正“超出范围”的是指令指针;该项目的评估目前正在一个对该项目不可见的范围内进行。但并不是范围内的所有东西都消失了!下次输入作用域时,静态变量仍然存在


“超出范围”不是很准确,但很短,每个人都理解它的含义。

当执行离开代码的这一部分时,在函数(或函数中某些用大括号括起来的结构)内声明的对象将超出范围

void some_func() {
  std::string x("Hello!");
  // x is in scope here
}
// But as soon as some_func returns, x is out of scope
这只适用于堆栈上声明的内容,因此它与单链接列表没有什么关系,因为列表节点通常会在堆上用
new
实例化

在本例中,当函数退出时,
new
返回的指针将超出范围,但节点本身不会发生任何变化:

void make_a_node() {
  Node* p = new Node;
} // Oh noes a memory leak!

首先,记住C++中的对象可以在堆栈<<强> >或在堆上<强>上创建。< /强>

堆栈帧(或范围)由语句定义。它可以与函数一样大,也可以与流量控制块一样小(
/
如果
/
用于
等)。包含任意代码块的任意
{}
对也构成堆栈帧。一旦程序退出该框架,框架内定义的任何局部变量都将超出范围。当堆栈变量超出范围时,将调用其析构函数

下面是一个堆栈帧(函数的执行)和其中声明的局部变量的经典示例,一旦堆栈帧退出,它将超出范围-一旦函数完成:

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.
下面是一个示例,我们看到堆栈帧只是
if
语句的主体:

if (myCondition) {
    Circle c (20);
    c.draw();
}
// c is now out of scope
// The destructor ~Circle() has been called
退出帧后,堆栈创建的对象“保留在范围内”的唯一方法是如果它是函数的返回值。但这并不是真正的“保留在范围内”,因为对象正在被复制。因此,原件超出了范围,但复制了一份。例如:

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.
现在,还可以在堆上声明对象。为了便于讨论,请将堆视为一个无定形的内存块。堆栈在进入和退出堆栈帧时自动分配和取消分配必要的内存,与此不同,您必须手动保留和释放堆内存

堆上声明的对象在堆栈帧之间以某种方式“存活”。可以说堆上声明的对象从未超出范围,但这确实是因为该对象从未真正与任何范围关联。此类对象必须通过
new
关键字创建,并且必须由指针引用

完成堆对象后,您有责任释放它。您可以使用
delete
关键字释放堆对象。在释放对象之前,不会调用堆对象上的析构函数

引用堆对象的指针本身通常是与作用域关联的局部变量。一旦使用完heap对象,就允许引用它的指针超出范围。如果尚未显式释放指针指向的对象,则在进程退出之前,堆内存块将永远不会被释放(这称为内存泄漏)

可以这样想:在堆栈上创建的对象就像一个绑在房间椅子上的气球。当你离开房间时,气球会自动弹出。在堆上创建的对象就像缎带上的气球,系在房间的椅子上。功能区是指针。当你离开房间时,缎带会自动消失,但是气球会浮到天花板上并占据空间。正确的程序是用别针弹出气球,然后离开房间,这时丝带就会消失。但是,绳子上的气球的好处是,你也可以解开丝带,拿在手里,然后离开房间,带上气球

因此,转到链表示例:通常,此类列表的节点在堆上声明,每个节点持有指向下一个节点的指针。所有这些都在堆上,永远不会超出范围。唯一的
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.
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