防止在C++中的指针上删除

Prevent delete on pointer in C++

本文关键字:指针 删除 C++      更新时间:2023-10-16

有没有办法防止通过声明删除C++中的指针?

我尝试过遵循代码,但没有运气。

const int* const foo()
{
    static int a;
    return &a;
}
int main()
{
    const int* const a = foo();
    *a = 1;   //compiler error, const int*
    a++;      //compiler error, int* const
    delete a; //no compiler error, I want to have compiler error here
    return 0;
}
不能

以防止在指针上调用delete的方式声明指向任意类型的指针。删除指向 const (T const*) 的指针解释了为什么会这样。

如果它是指向自定义类的指针,则可以将delete运算符设为私有:

class C {
    void operator delete( void * ) {}
};
int main() {
    C *c;
    delete c; // Compile error here - C::operator delete is private!
}

您当然不应该将析构函数设为私有(如其他人建议的那样),因为它也会避免在堆栈上创建对象:

class C {
    ~C() {}
};
int main() {
    C c; // Compile error here - C::~C is private!
}

简单的答案是否定的。无法防止在指向内置类型的指针上调用 delete。

增发:

但是,我遇到了与此类似的情况..我的解决方法是停止使用普通指针,因此无需担心删除。就我而言,共享指针是有意义的,但是唯一的指针或类似指针可能就足够了。

//Custom do nothing deleter.
template<typename T> dont_delete( T* ) { /* Do Nothing */ }
shared_ptr<const int> const foo()
{
  static int a;
  return shared_ptr<const int>(&a, &dont_delete<const int> );
}
shared_ptr<const int> const bar()
{
  return shared_ptr<const int>(new int(7) );
}
main()
{
   shared_ptr<const int> p1 = foo();
   shared_ptr<const int> p2 = bar();
   //p1s data _not_ deleted here, 
   //p2s data is deleted here
}

我不完全明白你在问什么。如果你想要一个无法删除的对象,你可以尝试将foo作为一个类,并使析构函数私有。

class Foo {
public:
   int a;
   Foo(int v) {
       a = b;
   }
private:
   ~Foo() { }
};
int main() {
    Foo *c = new Foo(1);
    delete c; // compiler error, ~Foo() is private
    return 0;
}

我公开了变量"a",因为它最初被定义为结构,但您可以(并且应该)将其设为私有,并使访问器强制执行您在原始代码示例中所需的访问规则。

这不是万无一失的,编译器只会捕获对该类的直接引用。

我认为他的意思是意外删除对象(无论是删除o还是free(o)),这可能导致程序崩溃。在堆上分配对象确实没有办法解决这个问题;就堆栈指针而言,我们都知道这不可能发生。在顶级类中使用受保护的 dtor 是一个选项,但您必须在子类 dtor 中调用它。

一种解决方案(即使覆盖删除运算符在表上)是使用返回 id/token/what-have-you 的表映射系统,但这实际上仅适用于您用 CSTYLE 代码编写和用 C 约定编译。这样做的好处是隐藏了来自用户的对象指针,允许用户传入映射到对象的令牌。这需要工作和经验才能完成。

我什至不会担心它,因为大多数经验和明智的程序员都会阅读 API 的文档以避免这种事故。如果下界明智或经验,好吧,那我就不该说了。

您可以阻止在某些类的指针上使用删除运算符。例如:

class Object {
public: void operator delete(void* p) = delete;
};
class Entity : public Object {    };
int main(int argc, char const *argv[])
{
    Object* o = new Object;
    Entity* e = new Entity;
    delete o; // compiler error
    delete e; // compiler error
    return 0;
}

对于从 Object 继承的所有类,无法删除,因为删除了 Object::运算符。不要将此运算符标记为私有,因为它会在派生或实例化 Object 类时给出编译器错误。请注意,我们仍然可以这样做:

::operator delete(o);

这将释放 o 指针,但不会调用析构函数。使用类来管理对象类的生存期。一个简单的实现是:

class Object {
    template<typename type> friend class ptr;
    public: void operator delete(void* p) = delete;
};
class Entity : public Object { };
template<typename type>
class Ptr {
public:
    Ptr(type* obj) : o(obj){}
    ~Ptr() { o->~type(); ::operator delete(o); }
private: type* o;
};
int main(int argc, char const *argv[])
{
    Object* o = new Object;
    Entity* e = new Entity;
    // delete o;  // error
    // delete e;  // error
    Ptr<Entity> ent = new Entity; // Ptr will delete ent for you.
    return 0;
}