局部变量的内存可以在其作用域之外访问吗?

2024-02-01

我有以下代码。

#include <iostream>

int * foo()
{
    int a = 5;
    return &a;
}

int main()
{
    int* p = foo();
    std::cout << *p;
    *p = 8;
    std::cout << *p;
}

并且代码只是运行,没有运行时异常!

输出是58

怎么会这样?局部变量的内存在其函数之外是不可访问的吗?


怎么会这样?局部变量的内存在其函数之外是不可访问的吗?

你租了一个酒店房间。你把一本书放在床头柜最上面的抽屉里,然后去睡觉。您第二天早上退房,但“忘记”归还钥匙。你偷了钥匙!

一周后,您回到酒店,没有办理入住,而是用偷来的钥匙潜入您的旧房间,然后查看抽屉。你的书还在那里。惊人!

怎么可能?酒店房间抽屉里的东西不是如果你没有租的房间就拿不到吗?

嗯,显然这种情况在现实世界中发生是没有问题的。当您不再被授权进入房间时,不会有任何神秘的力量导致您的书消失。也没有什么神秘的力量可以阻止你用偷来的钥匙进入房间。

酒店管理不required删除您的书。你没有与他们签订合同,规定如果你留下东西,他们会帮你把它撕碎。如果您用偷来的钥匙非法重新进入房间取回钥匙,酒店保安人员不会required你并没有和他们签订合同,上面写着“如果我稍后试图溜回我的房间,你必须阻止我”。相反,你和他们签了一份合同,上面写着“我保证以后不再溜回我的房间”,这份合同你打破了.

在这个情况下任何事情都可能发生。这本书可以在那里——你很幸运。别人的书可能在那里,而你的书可能在酒店的熔炉里。当你进来时,可能有人就在那里,把你的书撕成碎片。酒店本可以把桌子和书本全部拆除,换上一个衣柜。整个酒店可能即将被拆除,取而代之的是一个足球场,而你在偷偷摸摸的时候就会死于爆炸。

你不知道会发生什么;当你退房并偷了一把钥匙并稍后非法使用时,你就放弃了生活在一个可预测的、安全的世界中的权利,因为you选择打破制度规则。

C++ 不是一种安全的语言。它会很高兴地让你打破系统的规则。如果你试图做一些非法和愚蠢的事情,比如回到一个你无权进入的房间,翻阅一张可能已经不存在的桌子,C++ 不会阻止你。比 C++ 更安全的语言通过限制您的权力来解决这个问题,例如对密钥进行更严格的控制。

UPDATE

天哪,这个答案引起了很多关注。 (我不知道为什么——我认为这只是一个“有趣”的小比喻,但无论如何。)

我认为通过一些更多的技术想法来更新这一点可能是有意义的。

编译器的职责是生成代码来管理该程序操作的数据的存储。生成管理内存的代码有很多不同的方法,但随着时间的推移,两种基本技术已经变得根深蒂固。

第一个是拥有某种“长期存在”的存储区域,其中存储中每个字节的“生命周期”(即与某个程序变量有效关联的时间段)无法轻松提前预测。编译器生成对“堆管理器”的调用,该管理器知道如何在需要时动态分配存储空间并在不再需要时回收它。

第二种方法是使用“短期”存储区域,其中每个字节的生命周期是众所周知的。在这里,生命周期遵循“嵌套”模式。这些短期变量中寿命最长的变量将在任何其他短期变量之前分配,并且最后被释放。寿命较短的变量将在寿命最长的变量之后分配,并在它们之前释放。这些寿命较短的变量的生命周期“嵌套”在寿命较长的变量的生命周期内。

局部变量遵循后一种模式;当进入一个方法时,它的局部变量就会活跃起来。当该方法调用另一个方法时,新方法的局部变量就会激活。在第一个方法的局部变量失效之前它们就会失效。与局部变量相关的存储生命周期的开始和结束的相对顺序可以提前算出。

因此,局部变量通常生成为“堆栈”数据结构上的存储,因为堆栈具有这样的属性:第一个压入其中的东西将是最后一个弹出的东西。

就好像酒店决定只按顺序出租房间,直到房号比你高的人都退房之后你才能退房。

那么让我们考虑一下堆栈。在许多操作系统中,每个线程都有一个堆栈,并且堆栈被分配为特定的固定大小。当你调用一个方法时,东西就会被压入堆栈。如果您随后将指向堆栈的指针从方法中传回,就像原始发布者在这里所做的那样,那么这只是指向某个完全有效的百万字节内存块中间的指针。在我们的比喻中,你从酒店退房;当您这样做时,您刚刚从入住人数最多的房间退房。如果没有人在您之后办理入住,并且您非法返回房间,您的所有物品保证仍然在那里在这家特别的酒店.

我们使用堆栈作为临时存储,因为它们非常便宜且简单。 C++ 的实现不需要使用堆栈来存储局部变量;它可以使用堆。事实并非如此,因为这会使程序变慢。

C++ 的实现不需要将您留在堆栈上的垃圾原封不动地保留下来,以便您以后可以非法地返回;编译器生成将您刚刚腾出的“房间”中的所有内容归零的代码是完全合法的。并不是因为那样会很贵。

C++ 的实现不需要确保当堆栈逻辑收缩时,曾经有效的地址仍然映射到内存中。允许实现告诉操作系统“我们现在已经使用完这个堆栈页面了。除非我另有说明,否则如果有人接触了先前有效的堆栈页面,则发出一个异常,该异常会破坏进程”。同样,实现实际上并没有这样做,因为它很慢而且没有必要。

相反,实施会让你犯错误并侥幸逃脱惩罚。大多数时候。直到有一天,出现了真正可怕的问题,整个过程崩溃了。

这是有问题的。规则有很多,很容易不小心违反。我当然有很多次了。更糟糕的是,通常只有在损坏发生数十亿纳秒后检测到内存损坏时,问题通常才会出现,而此时很难找出是谁搞砸了。

更多内存安全语言通过限制你的能力来解决这个问题。在“普通”C# 中,根本无法获取本地地址并将其返回或存储以供以后使用。您可以获取本地地址,但该语言经过巧妙设计,使得在本地生命周期结束后无法使用它。为了获取本地地址并将其传回,您必须将编译器置于特殊的“不安全”模式,and在您的程序中添加“不安全”一词,以引起人们注意您可能正在做一些可能违反规则的危险事情。

进一步阅读:

  • 如果 C# 允许返回引用怎么办?巧合的是,这就是今天博客文章的主题:

    引用返回值和引用局部变量 https://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/

  • 为什么我们要用栈来管理内存呢? C# 中的值类型总是存储在堆栈中吗?虚拟内存如何工作?还有更多关于 C# 内存管理器如何工作的主题。其中许多文章也与 C++ 程序员密切相关:

    内存管理 https://ericlippert.com/tag/memory-management/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

局部变量的内存可以在其作用域之外访问吗? 的相关文章

  • Qt - 无法让 lambda 工作[重复]

    这个问题在这里已经有答案了 我有以下功能 我想在其中修剪我的std set
  • 在 C++ 中分割大文件

    我正在尝试编写一个程序 该程序接受一个大文件 任何类型 并将其分成许多较小的 块 我想我已经有了基本的想法 但由于某种原因我无法创建超过 12 kb 的块大小 我知道谷歌等上有一些解决方案 但我更感兴趣的是了解这个限制的根源是什么 然后实际
  • 捕获 foreach 条件中抛出的异常

    我有一个foreach在 foreach 本身的条件下循环期间中断的循环 有没有办法try catch抛出异常然后继续循环的项 这将运行几次 直到异常发生然后结束 try foreach b in bees exception is in
  • 有什么工具可以说明每种方法运行需要多长时间?

    我的程序的某些部分速度很慢 我想知道是否有我可以使用的工具 例如它可以告诉我可以运行 methodA 花了 100ms 等等 或者类似的有用信息 如果您使用的是 Visual Studio Team System 性能工具 中有一个内置分析
  • 在 Xcode4 中使用 Boost

    有人设置 C Xcode4 项目来使用 Boost 吗 对于一个简单的 C 控制台应用程序 我需要在 Xcode 中设置哪些设置 Thanks 用这个来管理它 和这个
  • std::map 和二叉搜索树

    我读过 std map 是使用二叉搜索树数据结构实现的 BST 是一种顺序数据结构 类似于数组中的元素 它将元素存储在 BST 节点中并按其顺序维护元素 例如如果元素小于节点 则将其存储在节点的左侧 如果元素大于节点 则将其存储在节点的右侧
  • ZLIB 解压缩

    我编写了一个小型应用程序 该应用程序应该解压缩以 gzip deflate 格式编码的数据 为了实现这一点 我使用 ZLIB 库 使用解压缩功能 问题是这个功能不起作用 换句话说 数据不是未压缩的 我在这里发布代码 int decompre
  • 是否有与 C++11 emplace/emplace_back 函数类似的 C# 函数?

    从 C 11 开始 可以写类似的东西 include
  • 范围和临时初始化列表

    我试图将我认为是纯右值的内容传递到范围适配器闭包对象中 除非我将名称绑定到初始值设定项列表并使其成为左值 否则它不会编译 这里发生了什么 include
  • C# 创建数组的数组

    我正在尝试创建一个将使用重复数据的数组数组 如下所示 int list1 new int 4 1 2 3 4 int list2 new int 4 5 6 7 8 int list3 new int 4 1 3 2 1 int list4
  • C# 编译器如何决定发出可重定向的程序集引用?

    NET Compact Framework 引入了可重定向程序集引用 现在用于支持可移植类库 基本上 编译器会发出以下 MSIL assembly extern retargetable mscorlib publickeytoken 7C
  • std::bind 重载解析

    下面的代码工作正常 include
  • 通过等待任务或访问其 Exception 属性都没有观察到任务的异常

    这些是我的任务 我应该如何修改它们以防止出现此错误 我检查了其他类似的线程 但我正在使用等待并继续 那么这个错误是怎么发生的呢 通过等待任务或访问其 Exception 属性都没有观察到任务的异常 结果 未观察到的异常被终结器线程重新抛出
  • 32位PPC rlwinm指令

    我在理解上有点困难rlwinmPPC 汇编指令 旋转左字立即然后与掩码 我正在尝试反转函数的这一部分 rlwinm r3 r3 0 28 28 我已经知道什么了r3 is r3在本例中是一个 4 字节整数 但我不确定这条指令到底是什么rlw
  • 如何检测 C# 中该字典键是否存在?

    我正在使用 Exchange Web 服务托管 API 和联系人数据 我有以下代码 即功能性的 但并不理想 foreach Contact c in contactList string openItemUrl https service
  • 无法使用 Ninject 将依赖项注入到从 Angular 服务调用的 ASP.NET Web API 控制器中

    我将 Ninject 与 ASP NET MVC 4 一起使用 我正在使用存储库 并希望进行构造函数注入以将存储库传递给其中一个控制器 这是实现 StatTracker 接口的上下文对象 EntityFramework public cla
  • 内核开发和 C++ [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 从我know https stackoverflow com questions 580292 what languages are windo
  • 为什么 Ajax.BeginForm 在 Chrome 中不起作用?

    我正在使用 c NET MVC2 并尝试创建一个 ajax 表单来调用删除数据库记录 RemoveRelation 的方法 删除记录的过程正在按预期进行 删除记录后 表单应调用一个 JavaScript 函数 从视觉效果中删除该记录 Rem
  • 以编程方式使用自定义元素创建网格

    我正在尝试以编程方式创建一个网格 并将自定义控件作为子项附加到网格中 作为 2x2 矩阵中的第 0 行第 0 列 为了让事情变得更棘手 我使用了 MVVM 设计模式 下面是一些代码可以帮助大家理解这个想法 应用程序 xaml cs base
  • Swagger 为 ASP.CORE 3 中的字典生成错误的 URL

    当从查询字符串中提取的模型将字典作为其属性之一时 Swagger 会生成不正确的 URL 如何告诉 Swagger 更改 URL 中字典的格式或手动定义输入参数模式而不自动生成 尝试使用 Swashbuckle 和 NSwag 控制器 pu

随机推荐

  • 如何为气流设置多个调度程序

    我们最近转向了气流 2 0 我想了解设置多个调度程序的过程 我尝试查看各种来源 包括使用天文学家 cli 的程序 但我们没有使用它 对于包括气流文档在内的其他来源 虽然他们提到可以这样做并给出了有关数据库要求的一些详细信息 但他们没有提供有
  • 以最佳方式返回负数的计数

    在按行和列排序的矩阵中搜索 的变体 给定一个按行和列排序的二维矩阵 您必须以最佳方式返回负数的计数 我可以想到这个解决方案 初始化行索引 0 如果行索引 gt 0 行索引 否则应用二分搜索 并用此代码实现 5X5 矩阵 include
  • 打印按值排序的字典

    我基本上是尝试迭代字典并从最大值到最小值打印出键 值 我一直在搜索这个网站 很多人都在使用 lambda 但我不太确定它是如何工作的 所以我现在试图避免它 dictIterator iter sorted bigramDict iterit
  • 如何在悬停时更改 navbarPage 链接的文本颜色(在闪亮的应用程序中)?

    这是我的闪亮应用程序的编辑版本 ui lt tagList fluidPage titlePanel tags head tags style HTML navbar default color red important navbarPa
  • PHP 对象生命周期

    我正在使用 PHP 5 2 如果我在一页上new一个对象 这个对象什么时候会被销毁 当用户转到另一个 php 页面时 对象是否会自动销毁 或者我需要显式调用 destructor 它将在页面加载结束时被破坏 从内存中卸载 或者如果您之前取消
  • SimpleXML 与 DOMDocument 性能对比

    我正在使用 SimpleXML 类构建 RSS 解析器 我想知道使用 DOMDocument 类是否会提高解析器的速度 我正在解析一个至少有 1000 行的 rss 文档 并且我使用了这 1000 行中的几乎所有数据 我正在寻找需要最少时间
  • 如何在 WPF 应用程序中为页面创建模式对话框?

    我有一个 WPF 窗口 其中有一个托管框架的控件 在该框架中我显示不同的页面 有没有办法使对话框仅在页面上模式化 当我显示对话框时 不应单击页面上的任何控件 但应该可以单击不在页面上的同一窗口上的控件 如果我对你的信息的解释是正确的 那么你
  • 正则表达式和 unicode

    我有一个脚本可以解析电视剧集的文件名 例如 show name s01e02 avi 获取剧集名称 来自 www thetvdb com API 并自动将它们重命名为更好的名称 节目名称 01x02 avi 该脚本工作正常 直到您尝试在具有
  • 检查 URL 是否有 http:// 前缀

    在我的应用程序中 当用户添加对象时 还可以添加该对象的链接 然后可以在 webView 中打开该链接 我尝试保存不带 http 前缀的链接 然后在 webView 中打开它 但无法打开它 在webView开始加载之前 有没有办法检查保存的U
  • 在 Dart 中发送 SMTP 电子邮件

    我查看了 API 文档和语言指南 但没有看到任何有关在 Dart 中发送电子邮件的内容 我也检查了这个谷歌群组帖子 https groups google com a dartlang org forum topic misc 5YNvrm
  • 如何通过 JSON 文件为curl 传递有效负载?

    我可以通过以下方式成功创建一个地方curl执行以下命令 curl vX POST https server api v1 places json d auth token B8dsbz4HExMskqUa6Qhn place name Fu
  • 为复杂的跨平台程序创建安装程序

    我正在为一堆相对复杂的桌面应用程序绘制一个应用程序部署过程 我们有本机应用程序和 Java 应用程序 因此部署必须能够检查 JRE 是否存在并在需要时安装它 某些应用程序依赖于特殊硬件 因此部署还必须能够启动必要的驱动程序安装程序 一些应用
  • 使用 AsyncTask 时应用程序挂起并暂停所有线程

    我正在尝试使用AsyncTask类来获取网站的内容 logcat 告诉我W art Suspending all threads took 15 or any other number ms反复 我的应用程序被冻结 直到日志消息打印完成 日
  • 在 Powershell 中设置 InheritanceFlags 与 PropagationFlags

    我正在尝试找到 InheritanceFlags 和 PropagationFlags 的正确组合 以便我的新文件夹不会继承之前文件夹的权限 而是将权限传播到新文件夹中包含的文件夹 文件 我尝试交换我下面有两个 但这只给了新文件夹与上面的文
  • 将三个不同的列合并为 R 中的日期

    现在 我在 R 的数据文件中有 3 个单独的列 分别为年 月和日 如何将这三列合并为一列并使 R 理解它是日期 这是现在的样子 year mon day gnp 1947 1 1 238 1 1947 4 1 241 5 1947 7 1
  • Elasticsearch 在显示 t: failed to read local state , exiting 后崩溃

    我是 Elasticsearch 的新手 我在本地只运行一个节点 到目前为止 它运行良好 现在一启动就崩溃了 错误堆栈如下 C MyApps elasticsearch6 5 1 elasticsearch oss 6 5 1 elasti
  • 在 bash 中从占据终端整个宽度的破折号字符绘制一条水平线

    我需要一个命令来在终端中绘制一条水平 线 该线必须恰好等于终端长的宽度 无论当前终端宽度如何 并且由破折号字符组成 尽管也可以使用水平线的 unicode 符号 如果能上色就更好了 我需要像这样使用它 echo some text draw
  • WCF:OperationContext.IncomingMessageProperties.Via 返回错误的 URI

    我在 IIS 中托管 WCF 服务 我在 IIS 中为该站点设置了多个主机名绑定 但是 当向任何非默认绑定发出请求时 OperationContext IncomingMessageProperties Via 属性不会报告正确的 url
  • 如何加载共享库而不加载其依赖项?

    说我有一个图书馆libfoo so 1 这取决于 根据ldd on libbar so 1 然而 libbar so 1目前不可用 我的应用程序需要调用一个函数libfoo so 1这不需要libbar so 1 at all 有没有办法加
  • 局部变量的内存可以在其作用域之外访问吗?

    我有以下代码 include