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

C++ 关于C+中的动态内存分配+;,c++,pointers,dynamic-allocation,C++,Pointers,Dynamic Allocation,假设我通过p1进行动态内存分配,如下所示 int* p1 = new int; *p1 = 1; 我知道p1引用的内存可以通过使用 delete p1; p1 = nullptr; 但是我想知道是否有另一个指针p2指向1,我可以删除该指针以释放内存吗?指针p1会发生什么情况?此外,p1和p2之间的关系本质上是什么?比如说, int* p1 = new int; *p1 = 1; int* p2 = p1; // Can I delete p2 like this? And what woul

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

int* p1 = new int;
*p1 = 1;
我知道
p1
引用的内存可以通过使用

delete p1;
p1 = nullptr;
但是我想知道是否有另一个指针
p2
指向
1
,我可以
删除该指针以释放内存吗?指针
p1
会发生什么情况?此外,
p1
p2
之间的关系本质上是什么?比如说,

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;

您可以删除
p2
,但取消引用
p1
将导致未定义的行为,以及可能的分段错误

它的工作原理如下:

  • 内存是在某个地址分配的
  • p1
    p2
    都指向此内存位置
  • 一旦
    p2
    删除-
    p1
    仍指向此内存位置。 没有泄漏,一切正常-只是不要取消引用
    p1
    。您可以自由执行
    p1=nullptr
    ,但不能执行
    *p1=1
    。此外,您不能删除
    p1
    ,因为它已经被删除,您可能会发现segfault

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

    有几种技术/模式可用于处理此问题。为此,通常使用智能指针。查看文档。不要使用过时的
    auto_ptr

    我最喜欢的模式是“所有权”。这意味着一个指针“拥有”分配,而所有其他指针只使用。这需要编程时遵守一定的规则,但一旦应用了这项工作,生成的代码就会清晰而简单。例如:

    class MyClass
    {
    public:  ~MyClass() { for(char *p: myStringsDict) delete p; }
    
    private:
        std::unordered_set<char*> myStringsDict;
    };
    
    class-MyClass
    {
    public:~MyClass(){for(char*p:myStringsDict)delete p;}
    私人:
    std::无序集myStringsDict;
    };
    
    看看这个类,很明显(尽管最好添加一个适当的注释),它拥有一个字符串字典,只要这个类的实例存在,这些字符串都是有效的。这些指针可以用在这个类所拥有的结构中,它们可以作为参数传递给函数等等。很明显,什么时候不应该再使用它们

    在多线程运行的服务器编程中,双重删除可能非常危险,并且很难跟踪。因为删除第一个指针后,内存将变为空闲内存,并且可以在不同的线程上分配用于其他目的。当第二个指针被释放时,它可能会删除一个有效的分配,而另一段代码对此一无所知,并继续使用这段内存

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

    指针p1会发生什么情况?此外,p1和p2之间的关系本质上是什么

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

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


    <>你留下了一个悬空指针,不能被安全删除。

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

    如果同时删除
    p1
    p2
    则会双重删除内存,这两个内存具有未定义的行为(在最佳情况下为崩溃),如果删除
    p1
    p2
    并通过另一个指针继续使用内存,则会使用悬空指针,这是未定义的行为(在最佳情况下为崩溃)。 您需要确保删除一个指针时,不要在其他指针中使用该内存

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

    auto p1 = std::make_shared<int>(0);
    auto p2 = p1;
    
    auto p1=std::make_shared(0);
    自动p2=p1;
    

    现在,最后一个活着的指针将删除分配的内存,您根本不必担心谁在删除什么

    让我们来探索房地产类比,内存扮演着土地的角色,指针扮演着地址的角色,这并不奇怪

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

     int *p = new int;
    
    你要求城市在某处找到一小块未使用的土地,并将所有权转让给你自己。你把它的街道地址写在黄色便条上

     *p = 1;
    
    你在那个地址建了一座整洁的小房子

      int *q = p;
    
    你把黄色便条复印一份。你忘记它有一段时间了

     delete p;
    
    你拆毁了这座建筑,放弃了你对这片土地的权利。城市可能会把它分配给其他人。也许有人想在那里再建一座小楼,或者铺设铁轨,或者建立一个鲨鱼池。注意:这对你的黄色笔记没有任何影响

    p = nullptr;
    
    你把一张黄色的钞票擦干净。你的另一个黄色音符挥之不去

    *q = 2;
    

    你找到另一张黄色便条,从上面读一个街道地址,然后假设土地是你的。糟糕的举动。你开始在别人的土地上建造一座整洁的小房子。新主人对此毫不在乎(他们无从知晓)。明天,他们可能会拆毁你的房子,把他们自己的房子安置好,或者用火车把你压垮,或者向你倾倒10万吨水和3个makos。那太不愉快了!不要触摸不属于你的东西。

    使用新it软件分配动态内存时
    delete p1;
    *p2 = 1;