繁体   English   中英

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

[英]memory questions, new and free etc. (C++)

关于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; } 

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

谢谢!

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

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

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

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

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

Mystruct S;

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

MyStruct *S = new MyStruct();

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

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

第一:

Mystruct* s = new Mystruct;

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

第二:

Mystruct s;

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

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

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

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

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

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

Mystruct * s = new Mystruct;

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

Mystruct s;

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

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

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

Q1:

Mystruct *s = new Mystryct;

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

Mystruct s;

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

Q2:

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

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

Mystruct *s = new Mystryct在堆上分配。
一个人需要明确删除它。
Mystruct s在堆栈上分配结构。
它会在堆栈展开时自动释放(变量超出范围),因此对于情况2,只要create()退出,tmp就会被释放。 所以你要归还的是一个dangling pointer which is very dangerousdangling 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。

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

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

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章)。

暂无
暂无

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

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