如果指针已经被删除,指针容器怎么能拥有指针的所有权

How can pointers container can have the ownership of pointers if pointers are already deleted?

本文关键字:指针 怎么能 拥有 所有权 删除 如果      更新时间:2023-10-16

在这段代码中,我试图创建一个模板类P_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指针吗?

否。

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

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

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

是公认的编程行为

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

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

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

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

  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>>

还有其他使用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