36

Is there any way to prevent deleting a pointer in C++ by its declaration?

I've tried following code without luck.

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;
}
Mircea Ispas
  • 20,260
  • 32
  • 123
  • 211

5 Answers5

39

You cannot declare a pointer to an arbitrary type in a way which prevents calling delete on the pointer. Deleting a pointer to const (T const*) explains why that is.

If it was a pointer to a custom class you could make the delete operator private:

class C {
    void operator delete( void * ) {}
};

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

You certainly shouldn't make the destructor private (as suggested by others) since it would avoid creating objects on the stack, too:

class C {
    ~C() {}
};

int main() {
    C c; // Compile error here - C::~C is private!
}
Community
  • 1
  • 1
Frerich Raabe
  • 90,689
  • 19
  • 115
  • 207
17

Simple answer is no. There is no way to prevent delete from being called on a pointer to built-in type.

ADDENDUM:

However I've run into similar situations to this .. my soltion was to stop using a normal pointer, and thus not need to worry about deletion. In my case a shared pointer made sense, but it yours a unique pointer or similar may suffice.

//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
}
Michael Anderson
  • 70,661
  • 7
  • 134
  • 187
1

I don't fully understand what you are asking. If you want an object that can't be deleted you can try making foo a class and make the destructor private.

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

I made variable "a" public since it was originally defined as a struct, but you can (and should) make it private and make accessors that enforce the access rules you wanted in your original code example.

This isn't foolproof and the compiler will only catch direct references to that class.

Bill C
  • 43
  • 2
0

I think what he means is accidental object deletion (whether delete o or free(o)) from happening which can result in a program crash. There really is no way around this with object allocated on the heap; as far as on the stack pointers we all know that it can't happen. Use protected dtor in top level classes is an option but then you are having to call on it in the child class dtor.

One solution (even though override the delete operator is on the table) is to use a table mapping system which returns an id/token/what-have-you but this really only works in your are writing in CSTYLE code and compiling in C conventions. The pro of doing this is hidden the object pointers from the user allow the user to pass in the token which in mapped to the object. This takes work and experience to do.

I wouldn't even worried about it because most experience and wise programmers read up on the API's documentation to avoid this mishaps. If nether wise or experience, well, I don't what to say then.

0

You can prevent the usage of delete operator on pointer of certain classes. For example:

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

For all classes that inherit from Object can not be deleted because the Object::operator delete was deleted. Don't mark this operator as private because it will give a compiler error when deriving or instantiating the Object class. Be aware that we can still do so:

::operator delete(o);

Which will free the o pointer but won't call the destructor. Use a class to manager the life time of the Object class. A simple implementation would be:

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;
}
Mateus Sarmento
  • 153
  • 1
  • 7