局部变量的内存可以在其范围之外访问吗? [英] Can a local variable's memory be accessed outside its scope?

查看:137
本文介绍了局部变量的内存可以在其范围之外访问吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码。

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

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

代码只运行没有运行时异常!

And the code is just running with no runtime exceptions!

输出 58

怎么办?

推荐答案


如何实现?

How can it be? Isn't the memory of a local variable inaccessible outside its function?

您租用酒店房间。你把一本书放在床头柜的顶部抽屉里,去睡觉。你第二天早上退房,但忘记给你的钥匙。你偷了钥匙!

You rent a hotel room. You put a book in the top drawer of the bedside table and go to sleep. You check out the next morning, but "forget" to give back your key. You steal the key!

一个星期后,你回到酒店,不办理入住手续,用你的钥匙偷进你的旧房间,看看抽屉。你的书还在那里。惊讶!

A week later, you return to the hotel, do not check in, sneak into your old room with your stolen key, and look in the drawer. Your book is still there. Astonishing!

怎么可能?如果您没有租房,酒店房间抽屉的内容是否不可访问?

很明显,这种情况可能发生在现实世界中没问题。没有神秘的力量,导致你的书消失,当你不再被授权在房间里。

Well, obviously that scenario can happen in the real world no problem. There is no mysterious force that causes your book to disappear when you are no longer authorized to be in the room. Nor is there a mysterious force that prevents you from entering a room with a stolen key.

酒店管理不是必须的,可以移除您的书籍。你没有与他们签订合同,说如果你留下东西,他们会为你撕碎。如果您非法使用被盗钥匙重新进入您的房间以取回钥匙,则酒店安全人员不需要 来捕捉您的偷盗行为。您没有与他们签订合同,说如果我试图偷偷回到我的房间后,你需要阻止我。相反,你与他们签订了一份合约,表示我保证不会后来偷偷回到我的房间,一个合同你突破了。

The hotel management is not required to remove your book. You didn't make a contract with them that said that if you leave stuff behind, they'll shred it for you. If you illegally re-enter your room with a stolen key to get it back, the hotel security staff is not required to catch you sneaking in. You didn't make a contract with them that said "if I try to sneak back into my room later, you are required to stop me." Rather, you signed a contract with them that said "I promise not to sneak back into my room later", a contract which you broke.

在这种情况下,会发生任何事情。这本书可以在那里 - 你有幸运。别人的书可以在那里,你的可以在酒店的炉子。当你进来,有人可以在那里,把你的书撕裂。酒店可以把桌子和书完全取代了一个衣柜。整个酒店可能即将被拆除,更换为一个足球场,你会在爆炸,而你偷偷摸摸死亡。

In this situation anything can happen. The book can be there -- you got lucky. Someone else's book can be there and yours could be in the hotel's furnace. Someone could be there right when you come in, tearing your book to pieces. The hotel could have removed the table and book entirely and replaced it with a wardrobe. The entire hotel could be just about to be torn down and replaced with a football stadium, and you are going to die in an explosion while you are sneaking around.

你不知道会发生什么;当您签出酒店并窃取了以后非法使用的钥匙时,您放弃了生活在可预测的安全世界的权利,因为您选择违反系统规则。

You don't know what is going to happen; when you checked out of the hotel and stole a key to illegally use later, you gave up the right to live in a predictable, safe world because you chose to break the rules of the system.

C ++不是安全的语言。它会高兴地允许你打破系统的规则。如果你试图做一些非法和愚蠢的事情,回到一个房间,你没有被授权进入和通过一个书桌,甚至可能不再有,通过C ++不会阻止你。

C++ is not a safe language. It will cheerfully allow you to break the rules of the system. If you try to do something illegal and foolish like going back into a room you're not authorized to be in and rummaging through a desk that might not even be there anymore, C++ is not going to stop you. Safer languages than C++ solve this problem by restricting your power -- by having much stricter control over keys, for example.

圣洁的好处,这个答案得到了很多的关注。 (我不知道为什么 - 我认为它只是一个有趣的小比喻,但无论如何。)

Holy goodness, this answer is getting a lot of attention. (I'm not sure why -- I considered it to be just a "fun" little analogy, but whatever.)

我认为这可能是更新

编译器在生成代码的业务中,它管理由该程序操作的数据的存储。有很多不同的方式来生成代码来管理内存,但随着时间的推移,两种基本技术已经根深蒂固。

Compilers are in the business of generating code which manages the storage of the data manipulated by that program. There are lots of different ways of generating code to manage memory, but over time two basic techniques have become entrenched.

第一种方法是使用某种长寿命存储区域,其中存储中每个字节的生命周期 - 即它有效地与一些程序变量相关 - 不能提前轻松预测。编译器生成对堆管理器的调用,知道如何在需要时动态分配存储,并在不再需要时进行回收。

The first is to have some sort of "long lived" storage area where the "lifetime" of each byte in the storage -- that is, the period of time when it is validly associated with some program variable -- cannot be easily predicted ahead of time. The compiler generates calls into a "heap manager" that knows how to dynamically allocate storage when it is needed and reclaim it when it is no longer needed.

第二个是具有某种短期存储区域,其中存储中的每个字节的寿命是众所周知的,并且特别地,存储器的寿命遵循嵌套模式。也就是说,短期变量中最长寿命变量的分配与它之后的短期变量的分配严格重叠。

The second is to have some sort of "short lived" storage area where the lifetime of each byte in the storage is well known, and, in particular, lifetimes of storages follow a "nesting" pattern. That is, the allocation of the longest-lived of the short-lived variables strictly overlaps the allocations of shorter-lived variables that come after it.

局部变量遵循后一种模式;当输入方法时,其局部变量活动。当该方法调用另一个方法时,新方法的局部变量生效。它们会在第一个方法的局部变量死掉之前死掉。

Local variables follow the latter pattern; when a method is entered, its local variables come alive. When that method calls another method, the new method's local variables come alive. They'll be dead before the first method's local variables are dead. The relative order of the beginnings and endings of lifetimes of storages associated with local variables can be worked out ahead of time.

因为这个原因,局部变量通常是作为存储生成的在一个堆栈数据结构,因为一个堆栈具有的第一件事推送它将是最后一个弹出的属性。

For this reason, local variables are usually generated as storage on a "stack" data structure, because a stack has the property that the first thing pushed on it is going to be the last thing popped off.

这就像酒店决定只按顺序租房,您不能退房,直到房间号高于您的所有人都签出。

It's like the hotel decides to only rent out rooms sequentially, and you can't check out until everyone with a room number higher than you has checked out.

让我们来思考一下这个堆栈。在许多操作系统中,每个线程获得一个堆栈,并且堆栈被分配为一定的固定大小。当你调用一个方法,东西被推到堆栈。如果你然后传递一个指向堆栈的指针返回你的方法,正如海报在这里,这只是一个指向一个完全有效的百万字节内存块的中间的指针。在我们的类比,你退房的酒店;当你做,你刚刚检出了最高编号的占用房间。如果没有其他人在您之后签到,并且您非法回到您的房间,您的所有资料都会保证在这个特定的酒店

So let's think about the stack. In many operating systems you get one stack per thread and the stack is allocated to be a certain fixed size. When you call a method, stuff is pushed onto the stack. If you then pass a pointer to the stack back out of your method, as the original poster does here, that's just a pointer to the middle of some entirely valid million-byte memory block. In our analogy, you check out of the hotel; when you do, you just checked out of the highest-numbered occupied room. If no one else checks in after you, and you go back to your room illegally, all your stuff is guaranteed to still be there in this particular hotel.

我们使用堆栈作为临时商店,因为它们真的便宜和容易。 C ++的实现不需要使用堆栈存储本地;它可以使用堆。它不,因为这将使程序更慢。

We use stacks for temporary stores because they are really cheap and easy. An implementation of C++ is not required to use a stack for storage of locals; it could use the heap. It doesn't, because that would make the program slower.

C ++的实现不需要留下你在堆栈上留下的垃圾,以便你以后可以非法地回来;它是完全合法的编译器生成的代码,回到零一切在你刚刚腾出的房间。它不会再次,这将是昂贵的。

An implementation of C++ is not required to leave the garbage you left on the stack untouched so that you can come back for it later illegally; it is perfectly legal for the compiler to generate code that turns back to zero everything in the "room" that you just vacated. It doesn't because again, that would be expensive.

不需要C ++的实现,以确保当堆栈逻辑收缩时,地址过去有效仍然被映射到内存。该实现允许告诉操作系统我们现在使用这个堆栈页面,直到我说,否则,发出一个异常,如果任何人触及以前有效的堆栈页面,破坏过程。再次,实现并不实际上这样做,因为它是缓慢和不必要的。

An implementation of C++ is not required to ensure that when the stack logically shrinks, the addresses that used to be valid are still mapped into memory. The implementation is allowed to tell the operating system "we're done using this page of stack now. Until I say otherwise, issue an exception that destroys the process if anyone touches the previously-valid stack page". Again, implementations do not actually do that because it is slow and unnecessary.

相反,实现让你犯错误和逃避它。大多数时候。直到有一天,真正的可怕的错误和过程爆炸。

Instead, implementations let you make mistakes and get away with it. Most of the time. Until one day something truly awful goes wrong and the process explodes.

这是有问题的。有很多规则,很容易意外打破它们。我当然有很多次。更糟糕的是,这个问题通常只在表面上发生,当腐败发生后,检测到内存被破坏了几十亿纳秒,当很难弄清楚谁搞砸了。

This is problematic. There are a lot of rules and it is very easy to break them accidentally. I certainly have many times. And worse, the problem often only surfaces when memory is detected to be corrupt billions of nanoseconds after the corruption happened, when it is very hard to figure out who messed it up.

更多的记忆安全语言通过限制你的力量解决这个问题。在正常C#中,简单地没有办法获取本地的地址并返回它或存储它以供以后使用。你可以取一个本地的地址,但语言是巧妙的设计,使它是不可能使用它在本地端的生命周期。为了获取本地地址并将其传回,您必须将编译器置于特殊的不安全模式下,在程序中加入不安全字样,以引起注意事实上,你可能在做一些危险的,可能是违反规则。

More memory-safe languages solve this problem by restricting your power. In "normal" C# there simply is no way to take the address of a local and return it or store it for later. You can take the address of a local, but the language is cleverly designed so that it is impossible to use it after the lifetime of the local ends. In order to take the address of a local and pass it back, you have to put the compiler in a special "unsafe" mode, and put the word "unsafe" in your program, to call attention to the fact that you are probably doing something dangerous that could be breaking the rules.

如需进一步阅读:


  • 参考?巧合的是今天的博客主题:

  • What if C# did allow returning references? Coincidentally that is the subject of today's blog post:

http://blogs.msdn.com/b/ericlippert/archive/2011/06/23/ref-returns-and-ref-locals.aspx < a>

http://blogs.msdn.com/b/ericlippert/archive/2011/06/23/ref-returns-and-ref-locals.aspx

为什么要使用堆栈来管理内存? C#中的值类型是否始终存储在堆栈中?虚拟内存如何工作?和更多的话题如何C#内存管理器工作。这些文章中的许多文章也与C ++程序员密切相关:

Why do we use stacks to manage memory? Are value types in C# always stored on the stack? How does virtual memory work? And many more topics in how the C# memory manager works. Many of these articles are also germane to C++ programmers:

https://blogs.msdn.microsoft.com/ericlippert/tag/memory-management/

这篇关于局部变量的内存可以在其范围之外访问吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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