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