【问题标题】:How can pointers container can have the ownership of pointers if pointers are already deleted?如果指针已经被删除,指针容器如何拥有指针的所有权?
【发布时间】:2015-04-14 17:54:06
【问题描述】:

在这段代码中,我尝试创建一个模板 classP_array,它存储指向对象的指针,如下所示。只需模板类存储指针,如果在使用后未删除,则将其删除。所以我应该做一个NULL 检查。

尽管此问题已在其他问题中得到解决。我不太明白如何检查指针是否为 NULL。

在析构函数~P_array()中检查NULL指针无效。

我用std::shared_ptr 尝试了类似的方法来解释这个想法。

p_array 析构函数:

~P_array() {
    unsigned int i = 0;
    while(i < total)
    {
        if (t_array[i])        //Not effective
        {
            std::cout << "deleting " << t_array[i] << "\n" ;
            delete (t_array[i]); //Ownership of pointer
        }
        i++;
    }
}    

main.cpp:

#include <iostream>
#include <memory>
#include "p_array.h"


class Obj {
    public: ~Obj () { std::cout << "Deleting Obj...\n" ;}
};


int main() {
    P_array<Obj> ap;
    Obj * op[10];

    for (int i = 0; i < 10 ; i++)
    {
        op[i] = new (Obj);
        ap.add(op[i]);
    }
    std::shared_ptr <Obj> sp = std::make_shared<Obj>();
    //if (sp.get())  delete sp.get() ; // invalid pointer error
    sp.reset();

    //delete op[0] ;// gives double free error
}

所以我的问题很简单:

  1. 如果我删除存储在容器中的指针,该容器会删除析构函数中的指针,那么容器如何知道这些指针是否实际被删除?

  2. 删除指针是否会使其成为NULL 指针?

  3. 如果容器无法检查已删除的指针,那么它如何获得这些指针的所有权,例如 P_array 示例的情况?

【问题讨论】:

  • 删除指针不会使其为空。如果需要,您必须将其显式设置为 null(删除后)。如果你有一个完整的(更小更简单)MVCE,这会更容易。
  • @Cornstalks 感谢您提供信息,但删除“垃圾数据”或其他内容后的指针值应该是什么。是否可以检查已删除的指针
  • Barry's answer。指针值不受删除影响。指针指向的内存是无效的,但不能保证“无效”的含义:一些系统会用一些无效值(即0xdeadbeef或零或类似的东西)擦除内存区域。一些系统将保持内存不变。它是实现定义的。

标签: c++ pointers c++11


【解决方案1】:

如果我删除了一个存储在容器中的指针,该容器删除了析构函数中的指针,那么容器如何知道这些指针是否被正确删除?

它没有。指针除了它指向的对象的地址之外没有任何信息。如果您需要额外的信息来确定该对象是动态分配的,还是已被删除,您需要将其保存在其他地方,例如智能指针。

删除指针是否会使其成为 NULL 指针?

没有。

如果容器不能检查已删除的指针,那么它如何获得这些指针的所有权,例如 P_array 示例

使用std::unique_ptrstd::shared_ptr 之类的智能指针,具体取决于它应该拥有独占所有权还是共享所有权。

【讨论】:

    【解决方案2】:

    如果我删除存储在容器中的指针,该容器将删除 析构函数中的指针然后容器如何知道这些 指针真的被删除了吗?

    一个被广泛接受的编程行为是

    • 定义时初始化所有指针
    • 如果要删除它指向的对象,则将指针设置为 NULL
    • 在取消引用之前始终检查指针是否不为 NULL

    这个琐碎的编程规则将确保

    • 不会发生双重删除
    • 悬空指针不会导致崩溃
    • 取消引用无效指针不会使您的程序崩溃

    当然,如果您使用智能指针,上述所有问题都可以得到解决。应该使用的确切智能指针取决于您的设计。

    【讨论】:

      【解决方案3】:
      1. 如果容器拥有指针,那么它拥有指针。只是不要在容器外部删除它们。这就是容器的工作!任何外部删除都是不正确的。注意这段代码在语法上是正确的,只是错误的:

        {
            std::unique_ptr<int> up(new int(42));
            delete up.get();
           // oops, now deleted again
        }
        

        程序员知道不要这样做。

      2. 没有。它只是释放内存供以后使用,它不必触摸指针或将其指向的内存清零或类似的事情。

      3. 这是类合同的一部分。它只拥有指针。时期。析构函数应该无条件地删除它的指针,除非你向release()(借用unique_ptr的方法)它们提供了一种方法。

      请注意,在 C++11 中,您可以简单地将其实现为:

      template <typename T>
      using P_Array = std::vector<std::unique_ptr<T>>
      

      【讨论】:

        【解决方案4】:

        还有其他关于使用 std::unique_ptrstd::shared_ptr 的建议,您应该对其进行调查,然后使用,而不是做您似乎想要做的事情。

        如果您想保留或多或少的代码,那么您需要了解一件事,那就是您的类 P_array 应该拥有它包含的指针。

        为此,您的析构函数应该是:

        ~P_array() {
            unsigned int i = 0;
            while(i < total)
            {
                std::cout << "deleting " << t_array[i] << "\n" ;
                delete t_array[i];  //Ownership of pointer
                i++;
            }
        }
        

        请注意,您不必在此处测试null 指针,因为delete 0;nop

        我注意到在main.cpp 中,您将指针存储在两个不同的容器中,但是当您调用ap.add(op[i]); 时,您必须想一想ap 现在拥有该指针。

        稍后你有一个注释掉的delete op[0];,它给了你一个双重删除。你应该做的是这样的:

        ap.t_array[0] = 0;  // Null the pointer so that ap no longer owns it.
        delete op[0];  // Delete pointer from the copy.
        

        您的控制台输出将包括:

        删除0

        【讨论】:

          猜你喜欢
          • 2012-07-07
          • 2012-03-18
          • 2010-09-08
          • 1970-01-01
          • 2013-06-01
          • 2020-06-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多