将指针分配给指针(并将指针传递给类)时使用删除的 C++ 混淆

Posted

技术标签:

【中文标题】将指针分配给指针(并将指针传递给类)时使用删除的 C++ 混淆【英文标题】:C++ Confusion using delete when asigning a pointer to a pointer (and passing pointers to classes) 【发布时间】:2011-11-24 11:57:23 【问题描述】:

对不起,如果我的上一个问题非常相似,但我还有一个关于何时以及是否应该使用 delete 关键字的查询。

示例代码。

我初始化了一个以指针向量作为参数的类。这些对象从堆中分配内存。然后我将这些对象传递给我的类构造函数,该构造函数也从堆中分配了内存。

代码如下: 在主函数中

     //This will also change each loop
     vector<A*>* ex1 = new vector<A*>;
     vector<B*>* ex2 = new vector<B*>;         
     vector<C*>* ex3 = new vector<B*>;

     for(int i =0; i < 10; i++)

       ex1->push_back( new A(i); );
       ex2->push_back( new B(i); );
       ex3->push_back( new C(i); );

     


     MainClass* ex_main = new MainClass(ex1,ex2,ex3);

在 MainClass.cxx 中

   MainClass::MainClass(vector<A*>* ex_A, vector<B*>* ex_B, vector<C*>* ex_C): m_ex_A(ex_A), m_ex_B(ex_B), m_ex_C(ex_C) 

在 MainClass.h 中

   vector<A*>* m_ex_A;
   vector<B*>* m_ex_B;         
   vector<C*>* m_ex_C;

m_ex1、m_ex2 和 m_ex3 已分配到堆栈,但已分配给指向指针向量的指针。

问题。

我是否删除了 MainClass 类的析构函数中的 m_ex_A,B 和 C(我知道我也需要删除每个向量中的元素)以及指向 main 函数中指针向量的指针?

例如在 MainClass 的析构函数中(我做了一些比这更通用的事情,但这更快显示)

for(int i = 0; i < m_ex_A->size(); i++)
     delete m_ex_A->at(i);
 

  delete m_ex_A;

然后我会在 main 函数中对指针向量 ex1、ex2、ex3 的指针执行类似的方法,并删除主类。

我的困惑来自于 m_ex_A、B 和 C 被分配给堆栈而不是动态分配的事实,但它们被分配给动态对象?

我的猜测是对 m_ex_A、B、C 对象使用删除,因为我已经动态初始化了它们?

还有什么是使用堆内存或堆栈更有效??

我想我可能使用了很多动态内存...

【问题讨论】:

使用堆栈在性能方面肯定会更高效。如果您确实不需要,请不要使用动态分配。 您正在混合使用“矢量”和“矢量”。他们应该是不同的,还是这是一个错字?向量应该是“std::vector”吗? @FabioFracassi 抱歉打错了 【参考方案1】:

您绝对应该在某处删除动态分配的对象。也可以将其作为MainClass 的析构函数,但就个人而言,我认为这是一种糟糕的风格。为什么?因为您在不同的地方、不同的实体中分配和删除。事实上,您正在转移这些对象的所有权,因此您应该非常小心不要删除两次或其他内容。我宁愿使用shared_ptrunique_ptr 并让我忘记所有这些微观管理。您可以在网络上搜索它们,它们非常易于使用。

至于第二个问题 - 您必须只删除每个对象一次。复制指针不会创建新对象,它只是指向同一对象的另一个指针。

【讨论】:

你回答了我的问题一半。如果我在课堂上删除,我还想在主函数中删除它们吗?我在这里感到困惑,因为堆栈中的对象指向堆中对象的地址? 不,你只删除一处!如果您将其删除两次,那就是 UB(未定义行为),这是您不想访问的地方 @FabioFracassi 所以这个 UB 是因为我已经释放了内存。我想这在我脑海中已经很清楚了。当我将它传递给班级时,当我想到它会改变所有权时,这对我来说是有意义的。 @MWright 您在 MainClass 的构造函数中所做的事情称为浅拷贝。您传递了指针,而不是那些指针复制到的内存。您需要确保只删除该内存一次(最好在您分配它的同一实体中),并且一旦它们指向的内存被删除,您就不会取消引用这些指针。【参考方案2】:

这不是对问题的直接回答,而是试图澄清根本问题:

概念上的问题是 原始 指针不传达(更糟糕的是没有办法)所有权信息。它们只是指向内存位置的指针。

现在,每当您使用new 分配动态内存时,您都有责任将其删除某处。 决定这个地方在哪里是设计程序的一部分。如果您将指针传递给示例中的某个对象,则需要记录该对象是否拥有指向内存的传入的所有权(在这种情况下,该对象负责清理)或者是否没有(并且调用者仍然负责)。

使用原始指针无法知道(除了文档或检查实现)任何给定函数是否具有所有权。

这是新的 C++11(也可从 boost 中获得)smart 指针(unique_ptrshared_ptr)适合的地方。它们立即传达谁负责删除内存和更好地自动执行此操作(并且很少或在 unique_ptr 无开销的情况下)

所以作为最后的指导方针:永远不要使用原始指针而不是智能指针或其他类型的 RAII 机制! (直到您在这些方面获得更多经验并且可以证明在这种特殊情况下原始指针实际上是更好的解决方案)

【讨论】:

如果类或函数拥有原始指针的所有权,并且我删除了这些类和函数之外的原始指针。它还会释放内存吗(我知道无法知道谁拥有所有权)? 我不明白你的问题。当您第一次执行delete some_ptr 时,指向的内存将被释放。如果指针被使用(即取消引用或删除),任何其他仍然拥有指针副本(指向现在释放的内存)的人现在都会遇到 UB。因此,如果您的对象获得所有权(即使用指向的内存)并且您在外部删除它,它将被删除并可能在您的对象内部造成严重破坏。 感谢您的帮助。我认为它终于沉没了:-p

以上是关于将指针分配给指针(并将指针传递给类)时使用删除的 C++ 混淆的主要内容,如果未能解决你的问题,请参考以下文章

将const引用/指针传递给类进行存储的首选方法,而不是复制引用的对象

如何在 STL 中使用指向向量的指针,就像我们在将数组地址传递给另一个函数时将指针分配给数组一样?

将指针传递给保证归零的内存

当我取消引用指针并将值分配给某个变量时,内存会发生啥?

如何将“this”指针传递给 C++ WinAPI 线程?

无法分配给 C++ 中的指针数组