【问题标题】:Why can't access a variable declared with new outside of the scope it was declared in?为什么不能在声明的范围之外访问用 new 声明的变量?
【发布时间】:2020-07-31 16:40:01
【问题描述】:

我知道这是一个愚蠢的问题,我无法理解我是如何陷入困境的,但我在这里。 在这段代码中,当我尝试在它声明的范围之外访问 x (在堆上声明)时,它告诉我 x 没有在这个范围内声明

{
    int * x = new int;
}
*x = 5; /// Error

我以前从未遇到过这个问题。在我致电delete x; 之前,x 不应该存在吗?

【问题讨论】:

  • 我从来没有遇到过这个问题你用的是什么C++?...
  • 我在 C++11 和 C++17 中尝试过。我很确定这只是我忘记的东西
  • 这里有多个概念,到目前为止,没有一个答案能正确解决。范围确定在源代码中标识符(名称)的可见位置。一个单独的概念,生命周期,是在程序执行期间可以使用对象的时间。对于某些对象,特别是那些具有自动存储持续时间的对象,生命周期与范围相关(当其关联块的执行结束时,生命周期将不复存在)。但这并不意味着您不能访问其范围之外的对象。您可以通过在接收到它的指针的子例程中访问它。

标签: c++ pointers scope heap-memory


【解决方案1】:

x(一个指针)和它指向的东西(一个 int)是有区别的。

int 不是“在堆上声明的”——堆不是作用域,也不包含声明。另一方面,x 只是堆栈上的一个普通变量,当其包含块的执行完成时会消失。

堆上的int 确实继续存在于堆上,但是当您丢弃x(指针)时,您将无法访问它并且int 已泄漏。

【讨论】:

  • 关于终生结束的措辞应该小心。具有自动存储持续时间的对象的生命周期在其关联块的执行结束(完全终止)时结束,而不仅仅是在执行离开块时,也许是暂时的。例如,当子程序被调用时,程序块的执行被暂停,子程序被执行,当子程序返回时,程序块的执行重新开始。在该子例程调用(以及它调用的任何其他内容)期间,该对象仍然存在并且仍然可以访问。
【解决方案2】:

声明某事与初始化某事不同,事实上是这样的:

{
    int * x = new int;
}
*x = 5; /// Error

永远不会工作(至少在 C++ 中),但是这个:

int* x;
{
    x = new int;
}
*x = 5; 

会起作用,因为x 的声明和使用在同一个范围内

【讨论】:

  • 嗯,这与堆栈上声明的变量相同。但是堆的想法是,当您声明某些内容时,除非您明确这样做(delete 关键字),否则它不会被删除。还是我只是把事情搞砸了?
  • @H-005 仅仅因为某些东西存在并不意味着您可以访问它。
  • @H-005 事实上x 在堆栈内,是指向堆中的东西,这就是为什么在你的例子中你得到一个错误,因为因为@ 987654326@在栈中,当其作用域结束时,将被释放
  • 哦。谢谢,我现在明白了。我可以发誓我以前做过这样的事情,但我很可能把事情搞砸了
【解决方案3】:

变量x只能在声明的范围内访问。

无论x 的状态如何,分配的缓冲区都会一直保留直到被删除,因此当x 在缓冲区被删除之前变得不可用并且在存储到x 的指针被复制到任何可用的任何位置之前,就会发生内存泄漏范围之外。

【讨论】:

  • 这就是 C++ 智能指针如此棒的原因,它们使内存泄漏的可能性大大降低。
  • Re“变量x只能在声明的范围内访问。”:标识符“x”只在其范围内是已知的。对象x 可能在程序中的任何地方都可以访问(例如通过将其地址传递给子程序)。对象的可访问性受生命周期限制,而不是受范围限制。范围是在程序源代码中标识符可见的地方。生命周期是一个对象在 C++ 模型中“存在”时。
【解决方案4】:

为什么不能在声明它的范围之外访问用 new 声明的变量?

因为语言规则说变量名的作用域已经结束:

[basic.scope.declarative]

每个名称都在程序文本的某个部分引入,称为声明区域,该区域是该名称有效的程序的最大部分,也就是说,该名称可以用作非限定名称来引用同一个实体。 通常,每个特定名称仅在程序文本的某个可能不连续的部分(称为其范围)内有效。

在块中声明的名称([stmt.block])是该块的本地名称;它具有块范围。 它的潜在作用域从其声明点 ([basic.scope.pdecl]) 开始,在其块的末尾结束

此外,随着名称的范围,对象的生命周期也结束了,因此由变量命名的对象不再存在于块范围之外。


在我调用 delete x; 之前 x 不应该存在吗?

没有。您混淆了具有自动存储功能的变量xx 指向的动态对象。动态对象仍然存在,但无法访问,因为您丢失了指针。这种只丢失指向动态内存的指针称为内存泄漏。

【讨论】:

    猜你喜欢
    • 2018-01-03
    • 2016-05-10
    • 1970-01-01
    • 2012-08-27
    • 1970-01-01
    • 1970-01-01
    • 2020-08-16
    • 2018-01-06
    • 1970-01-01
    相关资源
    最近更新 更多