简体   繁体   English

何时在C ++中从内存中删除变量?

[英]When are variables removed from memory in C++?

I've been using C++ for a bit now. 我现在一直在使用C ++。 I'm just never sure how the memory management works, so here it goes: 我只是不确定内存管理是如何工作的,所以在这里:

I'm first of all unsure how memory is unallocated in a function, ex: 我首先不确定函数中的内存是如何分配的,例如:

int addTwo(int num)
{
    int temp = 2;
    num += temp;
    return num;
}

So in this example, would temp be removed from memory after the function ends? 那么在这个例子中,函数结束后是否会从内存中删除? If not, how is this done. 如果没有,这是怎么做的。 In C# a variable gets removed once its scope is used up. 在C#中,一旦变量用完,变量就会被删除。 Are there also any other cases I should know about? 还有其他我应该知道的案例吗?

Thanks 谢谢

In C++ there is a very simple rule of thumb: 在C ++中有一个非常简单的经验法则:

All memory is automatically freed when it runs out of scope unless it has been allocated manually. 除非已手动分配,否则当超出范围时,将自动释放所有内存。

Manual allocations: 手动分配:

  • Any object allocated by new() MUST be de-allocated by a matching delete(). new()分配的任何对象必须由匹配的delete()取消分配。
  • Any memory allocated by malloc() MUST be de-allocated by a matching free(). malloc()分配的任何内存必须由匹配的free()解除分配。

A very useful design pattern in C++ is called RAII ( Resource Acquisition Is Initialization ) which binds dynamic allocations to a scoped object that frees the allocation in its destructor. C ++中一个非常有用的设计模式称为RAII资源获取是初始化 ),它将动态分配绑定到一个作用域对象,从而释放其析构函数中的分配。

In RAII code you do not have to worry anymore about calling delete() or free() because they are automatically called whenever the "anchor object" runs out of scope. 在RAII代码中,您不必再担心调用delete()或free(),因为只要“锚点对象”超出范围,就会自动调用它们。

Here, temp is allocated on the stack, and the memory that it uses is automatically freed when the function exits. 这里, temp被分配在堆栈上,当函数退出时,它自动释放它使用的内存。 However, you could allocate it on the heap like this: 但是,您可以在堆上分配它,如下所示:

int *temp = new int(2);

To free it, you have to do 要解放它,你必须这样做

delete temp;

If you allocate your variable on the stack, this is what typically happens: 如果在堆栈上分配变量,通常会发生这种情况:

When you call your function, it will increment this thing called the 'stack pointer' -- a number saying which addresses in memory are to be 'protected' for use by its local variables. 当你调用你的函数时,它会增加这个称为“堆栈指针”的东西 - 一个数字,说明内存中的哪些地址被“保护”以供其局部变量使用。 When the function returns, it will decrement the stack pointer to its original value. 当函数返回时,它会将堆栈指针递减到其原始值。 Nothing is actually done to the variables you've allocated in that function, except that the memory they reside in is no longer 'protected' -- anything else can (and eventually will) overwrite them. 实际上没有对你在该函数中分配的变量进行任何操作,除了它们所在的内存不再受“保护” - 其他任何东西都可以(并最终将)覆盖它们。 So you're not supposed to access them any longer. 所以你不应该再访问它们了。

If you need the memory allocated to persist after you've exited the function, then use the heap. 如果在退出函数后需要分配的内存保持不变,则使用堆。

The local variable temp is "pushed" on a stack at the beginning of the function and "popped" of the stack when the function exits. 局部变量temp在函数开始时被“推”到堆栈上,并在函数退出时“弹出”堆栈。

Here's a disassembly from a non optimized version: 这是非优化版本的反汇编:

int addTwo(int num)
{
00411380  push        ebp  
00411381  mov         ebp,esp             //Store current stack pointer
00411383  sub         esp,0CCh            //Reserve space on stack for locals etc
00411389  push        ebx  
0041138A  push        esi  
0041138B  push        edi  
0041138C  lea         edi,[ebp-0CCh] 
00411392  mov         ecx,33h 
00411397  mov         eax,0CCCCCCCCh 
0041139C  rep stos    dword ptr es:[edi] 
    int temp = 2;
0041139E  mov         dword ptr [temp],2 
    num += temp;
004113A5  mov         eax,dword ptr [num] 
004113A8  add         eax,dword ptr [temp] 
004113AB  mov         dword ptr [num],eax 
    return num;
004113AE  mov         eax,dword ptr [num] 
}
004113B1  pop         edi  
004113B2  pop         esi  
004113B3  pop         ebx  
004113B4  mov         esp,ebp                 //Restore stack pointer
004113B6  pop         ebp  
004113B7  ret        

The terms "pushed" and "popped" are merely meant as an analogy. 术语“推”和“弹出”仅仅意味着类比。 As you can see from the assembly output the compiler reserves all memory for local variables etc in one go by subtracting a suitable value from the stack pointer. 从汇编输出中可以看出,编译器通过从堆栈指针中减去合适的值,一次性保留局部变量等的所有内存。

Its not removed from memory once the function exits. 一旦函数退出,它就不会从内存中删除。

It remains in memory, in addTwo's stack frame, until some other process (or the same) re uses that portion of memory. 它保留在内存中,在addTwo的堆栈帧中,直到某个其他进程(或相同)重新使用该部分内存。

Until that point, accessing temp is undefined behaviour. 在此之前,访问temp是未定义的行为。

temp is allocated on the stack. temp在堆栈上分配。 So when the function returns, it is gone. 所以当函数返回时,它就消失了。

C++ scope rules are similar to C#. C ++范围规则与C#类似。

Please see my answer to this question. 请看我对这个问题的回答。 It may clear up a lot of things for oyu. 这可能会为oyu清理很多东西。

How does automatic memory allocation actually work in C++? 自动内存分配如何在C ++中实际工作?

I'm not just posting a link for giggles. 我不只是发布咯咯笑的链接。 My answer there is an in-depth look (at a very introductory level) how memory management works. 我的答案是深入了解(在介绍性层面)内存管理的工作原理。

Normally memory managment is used in the context of dynamic memory that is created by 通常,内存管理用于创建的动态内存的上下文中

new
malloc

In the normal code C++ behaves like every other language. 正常的代码中,C ++的行为与其他语言类似。 If you create a variable or return it, it is copied and accessible on the target side. 如果您创建变量或将其返回,则会在目标端复制并访问该变量。

int a = addTwo(3);

gets a copy of your returned value. 获取返回值的副本。 If the returned value is a class copy operator called. 如果返回的值是一个调用的类复制操作符。 So as long as you do not work with new and malloc you do not have to care about memory managment that much. 因此,只要你不使用new和malloc,你就不必那么关心内存管理了。

One additional remark which is important 另外一个重要的评论

void func(std::string abc)
{
  // method gets a copy of abc
}

void func(std::string& abc)
{
  // method gets the original string object which can be modified without having to return it
}

void func(const std::string& abc)
{
  // method gets the original string object abc but is not able to modify it    
}

The difference of the three lines is very important because your program may spare a lot of time creating copies of input parameters that you normally didn't want to create. 这三行的区别非常重要,因为您的程序可能会花费大量时间创建通常不想创建的输入参数副本。

eg 例如

bool CmpString(std::string a, std::string b)
{
  return a.compare(b);
}

is really expensive because the strings a and b are always copied. 是非常昂贵的,因为字符串a和b总是被复制。 Use 使用

bool CmpString(const std::string& a, const std::string& b)

instead. 代替。

This is important because no refcounted objects are used by default. 这很重要,因为默认情况下不使用refcounted对象。

Variable temp is stack allocated. 变量temp是堆栈分配的。 That means it's deallocated when the function returns. 这意味着它在函数返回时被释放。

See eg: 见例如:

In this case both num and temp are local to this function. 在这种情况下,num和temp都是此函数的本地。 When the function is called the number passed into num is copied from the caller to a variable on the stack. 调用该函数时,传入num的数字将从调用者复制到堆栈上的变量。 Temp is then created on the stack. 然后在堆栈上创建Temp。 When you return the value of num is copied back to the caller, and the temp and num variables used in the function are dropped. 返回时,num的值被复制回调用者,并且函数中使用的temp和num变量将被删除。

In C,C++ local variables have automatic storage class and are stored in Stack . 在C中,C ++ 局部变量具有自动存储类并存储在Stack中

When function returns then stack gets unwound and locals are no more accessible, but they still persist in memory and that's the reason when u define a variable in function it may contain garbage value. 当函数返回时,堆栈被解开并且本地不再可访问,但它们仍然存在于内存中,这就是当你在函数中定义变量时它可能包含垃圾值的原因。

It is just stack pointer manipulation in stack and on memory for local is removed actually. 它只是堆栈中的堆栈指针操作,实际上是删除了本地的内存。

In C++, any object that you declare in any scope will get deleted when the scoped exits. 在C ++中,任何作用域中声明的任何对象都将在作用域退出时被删除。 In the example below, the default constructor is called when you declare the object and the destructor is called on exit, ie, ~MyClass. 在下面的示例中,在声明对象时调用默认构造函数,并在退出时调用析构函数,即~MyClass。

void foo() {
  MyClass object;
  object.makeWonders();
}

If you declare a pointer in a function, then the pointer itself (the 4 bytes for 32 bit systems) gets reclaimed when the scoped exits, but the memory you might have allocated using operator new or malloc will linger - this is often known as memory leak. 如果在函数中声明指针,那么当范围退出时,指针本身(32位系统的4个字节)会被回收,但是您可能使用operator new或malloc分配的内存将会延迟 - 这通常称为内存泄漏。

void foo() {
  MyClass* object = new MyClass;
  object->makeWonders();
  // leaking sizeof(MyClass) bytes.
}

If you really must allocate an object via new that needs to be deleted when it exits the scope then you should use boost::scoped_ptr like so: 如果你真的必须通过new分配一个对象,当它退出范围时需要删除,那么你应该使用boost :: scoped_ptr,如下所示:

void foo() {
  boost::scoped_ptr<MyClass> object(new MyClass);
  object->makeWonders();
  // memory allocated by new gets automatically deleted here.
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM