记忆问题,新的和免费的等等。(C ++)

时间:2010-02-04 08:09:31

标签: c++ memory free new-operator

我对C ++中的内存处理有几个问题。

  1. Mystruct *s = new MystructMystruct s的不同之处是什么?记忆中会发生什么?

  2. 查看此代码:

    struct MyStruct{
        int i;
        float f;
    };
    
    MyStruct *create(){
        MyStruct tmp;
        tmp.i = 1337;
        tmp.j = .5f;
        return &tmp;
    }
    
    int main(){
        MyStruct *s = create();
        cout << s->i;
    
        return 0;
    }
    
  3. MyStruct tmp何时免费? 为什么MyStruct tmp create()结束时{{1}}自动免费?

    谢谢!

9 个答案:

答案 0 :(得分:8)

当您使用new关键字获取指针时,您的结构将在堆上分配,以确保它将在应用程序的生命周期内持续存在(或直到它被删除)。

如果不这样做,结构将在堆栈上分配,并在分配范围终止时销毁。

我对你的例子的理解(如果我错了,请不要犹豫,告诉我),

tmp确实会在函数末尾被“释放”(不是堆栈变量的最佳单词选择),因为它是在堆栈上分配的并且堆栈帧已经丢失。你返回的指针/内存地址已经没有任何意义了,如果代码有效,你基本上就幸运了(还没有覆盖旧数据)。

答案 1 :(得分:3)

对于问题1,您正在查看堆内存和堆栈内存。简而言之,

Mystruct S;

在堆栈上创建S.当S超出范围时,它将被销毁。因此,如果S在函数内,当函数返回时,S被销毁。

尽管

MyStruct *S = new MyStruct();

在堆上。它是为程序存储变量而预留的一块内存,S将存储指向新MyStruct的起始内存块的指针。它会一直在堆里,直到你释放它;如果你的程序结束时没有释放它,你会得到恶意的内存泄漏。

问题2 - 当函数退出时,本地MyStruct被销毁;指向其返回值的MyStruct指针指向未定义的区域。它可能仍然有效,因为操作系统尚未回收内存,但它绝对不是正确的行为 - 或者是安全的事情。

答案 2 :(得分:1)

首先:

Mystruct* s = new Mystruct;

new Mystryct部分在堆上为该类型的对象分配内存。在C ++中,它还将执行该类型的默认构造函数。 Mystruct* s部分声明一个指针变量,该变量指向新分配的对象内存的第一个字节的地址。

第二

Mystruct s;

它的作用与第一个有两个不同,可以简化为:对象的已分配内存在堆栈上,并且没有指向内存的指针变量,而是s 那个对象。该对象的地址为&s,因此指向对象s的指针应分配值&s

  

为什么MyStruct tmp在create()结束时不会自动释放?

确实如此。 tmp析构函数在 return语句之后运行,因此函数返回的地址将是一个很快被其他东西覆盖的内存,这最多会导致分段错误(或等效的),最坏的情况是破坏您的数据。

答案 3 :(得分:1)

您的两个问题都涉及存储时间和范围。

首先,当您动态分配对象时,该对象及其指针在您释放之前一直有效。如果它是一个自动变量(即,不是由newmalloc等动态分配,而不是声明static),那么一旦对象的范围,变量就会超出范围结束(通常是}与定义对象的“级别”相同的“级别”。它还具有“自动存储持续时间”,这意味着当对象不在范围内时,它的存储也会消失。

对于第二个问题,tmp的范围以}的结尾create结尾。它也具有相同的存储持续时间。指向tmp的指针仅在该存储持续时间内有效。退出create()后,指向tmp的指针将变为无效,无法使用。

答案 4 :(得分:0)

Mystruct * s = new Mystruct;

在堆上动态分配s。它不会自动释放。 (另外,s是指针,不是直接的Mystruct)。

Mystruct s;

在堆栈上静态分配s。当它超出范围时,它将被“释放”。*

您的代码无效。当你在create之外引用tmp时,你正在使用一个野指针访问死记忆。这会导致未定义的行为。

  • 差不多。使用它超出范围是未定义的行为,即使该值仍在内存中。

答案 5 :(得分:0)

<强> Q1:

Mystruct *s = new Mystryct;

在堆上创建结构变量,该变量由变量s指向。

Mystruct s;

这里的结构是在堆栈上创建的。

<强> Q2:

MyStruct *create(){ MyStruct tmp; tmp.i = 1337; return &tmp; }

错了!!您正在堆栈上创建一个本地结构变量,当函数返回并且对它的任何引用都无效时,它会消失。你应该动态地分配变量,并且必须在以后用main手动解除分配。

答案 6 :(得分:0)

Mystruct *s = new Mystryct在堆上分配 需要明确删除它 而Mystruct s在堆栈上分配结构 它会在堆栈展开时自动释放(变量超出范围) 因此,对于案例2,只要create()退出,tmp就会被释放。所以你要归还的是dangling pointer which is very dangerous

如果太难,请遵循这条经验法则,
For every new operator called, delete must be called in the end.
For every new[] operator called, delete[] must be called in the end.

使用智能指针自动删除分配的内存而不是普通指针。 如果你从create中的函数返回对象,请确保使用new运算符分配它,而不是像在示例中那样在堆栈上分配它。确保调用者在完成后调用指针上的delete。

答案 7 :(得分:0)

  1. Mystruct *s = new Mystruct中,有一个静态变量,指针,在堆栈上的函数调用开始时分配。当这一行运行时,它在堆上分配struct。在Mystruct s中,它在堆栈上分配结构,“静态地”在函数运行时(构造函数,如果有的话,将在decleration行中运行)。

  2. “为什么MyStruct tmp在create()结束时不会自动释放?” - 好吧,是的。但是,内存仍然存在,因此您可以访问它,可能包含旧值。

答案 8 :(得分:0)

struct MyStruct{ int i; };

MyStruct create(){ MyStruct tmp; tmp.i = 1337; return tmp; }

int main(){

  MyStruct s = create();
  cout << s.i;

  return 0;
}

struct MyStruct{ int i; };

MyStruct* create(){ MyStruct* tmp = new MyStruct; tmp->i = 1337; return tmp; }

int main(){

  MyStruct* s = create();
  cout << s->i;
  delete s;    

  return 0;
}

会奏效。因为复制构造函数在第一种情况下将结构分配给s时会创建结构的副本。 全新的/删除内容(动态内存分配)属于C ++的基础。您不必使用任何新的或删除来实现基本算法。复制构造函数等将始终完成工作并使代码更容易理解。

如果你想使用new,你还应该阅读有关autopointer等内容。 C ++中没有内存的垃圾收集。 我认为Thinking C++很好地解释了动态记忆的概念(第13章)。