36

有什么方法可以防止通过声明删除 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;
}
4

5 回答 5

39

您不能以阻止调用指针的方式声明指向任意类型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!
}
于 2012-08-08T14:11:06.107 回答
17

简单的答案是否定的。没有办法阻止在指向内置类型的指针上调用 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
}
于 2012-08-08T14:10:44.830 回答
1

我不完全明白你在问什么。如果您想要一个无法删除的对象,您可以尝试将 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”设为公开,因为它最初被定义为结构,但您可以(并且应该)将其设为私有,并使访问器强制执行您在原始代码示例中想要的访问规则。

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

于 2012-08-08T14:18:16.423 回答
0

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

一种解决方案(即使覆盖删除操作符在表上)是使用一个表映射系统,它返回一个 id/token/what-have-you 但这真的只适用于你用 CSTYLE 代码编写和用 C 约定编译. 这样做的好处是对用户隐藏对象指针,允许用户传入映射到对象的令牌。这需要工作和经验。

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

于 2014-10-23T10:35:45.563 回答
0

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

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::operator delete 已被删除。不要将此运算符标记为私有,因为它会在派生或实例化 Object 类时产生编译器错误。请注意,我们仍然可以这样做:

::operator delete(o);

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

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;
}
于 2016-05-27T15:18:14.423 回答