防止在C ++中删除指针

时间:2012-08-08 14:01:36

标签: c++

有没有办法阻止在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;
}

5 个答案:

答案 0 :(得分:34)

您不能以阻止在指针上调用delete的方式声明指向任意类型的指针。 Deleting a pointer to 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!
}

答案 1 :(得分:15)

简单回答是。无法阻止在指向内置类型的指针上调用删除。

附录

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

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

答案 2 :(得分: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”设为public,因为它最初定义为结构,但您可以(并且应该)将其设为私有,并使访问器在原始代码示例中强制执行您想要的访问规则。

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

答案 3 :(得分:0)

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

一个解决方案(即使覆盖删除操作符在表上)是使用表映射系统,它返回一个id / token / what-have-you但这实际上只适用于你在CSTYLE代码中编写和编译在C约定中。执行此操作的专业人员隐藏了来自用户的对象指针,允许用户传入映射到对象的令牌。这需要工作和经验。

我甚至不担心,因为大多数经验和聪明的程序员都会阅读API的文档以避免这种不幸。如果幽默或经验,那么,我不知道该说些什么。

答案 4 :(得分:0)

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

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