关于C ++中的动态内存分配

时间:2016-11-27 15:43:03

标签: c++ pointers dynamic-allocation

假设我通过p1进行动态内存分配,如下所示,

int* p1 = new int;
*p1 = 1;

我知道可以使用

释放p1引用的内存
delete p1;
p1 = nullptr;

但是我想知道是否有另一个指针p2指向1,我可以delete这个指针来释放内存吗?指针p1会发生什么?另外,p1p2之间的关系本质上是什么?例如,

int* p1 = new int;
*p1 = 1;
int* p2 = p1;
// Can I delete p2 like this? And what would happen to p1?
delete p2;
p2 = nullptr;

6 个答案:

答案 0 :(得分:8)

您可以删除p2,但解除引用p1会导致未定义的行为和可能的细分错误。

它的工作原理如下:

  1. 内存分配在某个地址。
  2. p1p2都指向此内存位置。
  3. 删除p2后,p1仍指向此内存位置。 没有泄漏,一切都很好 - 只是不要取消引用p1。您可以自由p1 = nullptr,但不能*p1 = 1。此外,您无法删除p1,因为它已被删除,您可能会遇到段错误。

答案 1 :(得分:4)

你在(旧)C ++中描述一个非常已知的问题:当几个指针指向同一个动态内存时,哪一个删除它?

如果删除p1p2,则删除内存,如果删除p1或{{1,则会删除具有未定义行为的内存(崩溃,在最好的情况下)并且你继续通过另一个指针使用内存 - 你正在使用悬空指针,这是未定义的行为(崩溃,在最好的情况下)。 你需要确保当一个指针被删除时 - 你不要在其他指针中使用那个内存。

C ++ 11引入了一种处理这个问题的标准方法:使用自我计数指针,只有最后一个指针删除内存:

p2

现在,最后一个指针活动将删除已分配的内存,并且您不必担心所有删除内容的人。

答案 2 :(得分:2)

您可以删除p1p2。没有区别。但你不应该删除这两个。一旦你删除了一个,你不应该使用另一个。程序员对此负责。语言本身不会提供任何帮助。这里有很多不同的方法来编写错误的代码。

有几种技术/模式可以解决这个问题。通常使用智能指针。查看std::shared_ptr文档。不要使用过时的auto_ptr

我最喜欢的模式是“所有权”。这意味着一个指针“拥有”分配,而其他所有人只是使用。这需要在编程时遵循一定的规则,但是一旦应用了这些努力,结果代码就清晰而简单。例如:

class MyClass
{
public:  ~MyClass() { for(char *p: myStringsDict) delete p; }

private:
    std::unordered_set<char*> myStringsDict;
};

查看这个类很清楚(尽管添加一个适当的注释会很好)它拥有一个字符串字典,只要这个类的实例存在,这些字符串就是有效的。这些指针可以在这个类所拥有的结构中使用,它们可以作为参数传递给函数等。很明显它们不应再被使用了。

在多线程运行时的服务器编程中,双重删除可能非常危险且难以追踪。因为在删除第一个指针之后,内存变得空闲,并且可以在不同的线程上为其他目的分配。当第二个指针被释放时,可能会发生它正在删除有效分配而其他代码片段不知道这一点并继续使用这段内存。

对所有这些问题的真正好的解决方案是垃圾收集。当使用显式分配时,程序员需要以这种或那种方式应用额外的工作。

答案 3 :(得分:2)

  

指针p1会发生什么?另外,p1和p2之间的关系基本上是什么?

它们的基本关系是它们指向在赋值int* p2 = p1;之后从动态内存分配中获得的相同地址。

因此,删除其中任何一个都将释放分配的内存。将其中一个设置为nullptr但不会影响另一个。

所以你留下了一个无法安全删除的悬挂指针。

答案 4 :(得分:1)

让我们探讨一下房地产类比,其中记忆扮演着土地的角色,指针不是那么令人惊讶地充当地址。

指针变量是黄色便利贴。你可以在上面写一个街道地址。从免费商店分配的变量是某地址的一块土地。

 int *p = new int;

你要求城市在某处找到一小块未使用的土地并将标题分配给自己。你用黄色的纸条记下街道地址。

 *p = 1;

你在那个地址建造了一个整洁的小房子。

  int *q = p;

您复制了黄色音符。你有一段时间忘了它。

 delete p;

你拆除了建筑物并放弃了对这块土地的权利。城市可能会将其分配给其他人。也许有人想在那里建造另一座小楼,或者可能铺设铁轨或建立鲨鱼池。请注意,这对任何黄色音符都没有任何作用。

p = nullptr;

你擦干净的黄色纸条。你的另一张黄色纸条依旧。

*q = 2;

你找到了另一个黄色的纸条,读了一个很棒的地址,并假设土地是你的。不好的举动。你继续在别人的土地上建造一个整洁的小房子。新主人不能太在意(他们无从得知)。明天他们可能会拆除你的建筑物并将它们放在适当的位置,或者用火车超过你,或者将10万吨水和3个makos倾倒在你身上。这相当不愉快!别碰你不属于你的东西。

答案 5 :(得分:0)

当使用new分配动态内存时,它应该通过delete释放,只要你使用new创建p1然后使用delete释放它。 你将p2声明为指向同一内存的指针p1指向那么如果你想释放p1而不是p2的内存调用delete是可读的,但是可以通过调用p1上的delete来释放内存P2

如果你在p1上调用delete,那么让p2指向null,以免错误地取消引用它,因为写道:

delete p1;
*p2 = 1;

会导致未定义的行为。