禁止/重定向c++删除

Disallow/Redirect C++ delete?

本文关键字:删除 c++ 重定向 禁止      更新时间:2023-10-16

我有一个模块(dll/so),它导出一个单一的工厂函数,返回一个对象,然后调用。使用接口(纯虚拟),模块的用户可以创建不同的对象。所有的对象创建都是通过接口进行的,因此使用与我的模块相关联的运行时而不是应用程序运行时进行。

由于分配发生在模块内部,因此也需要删除,因为如果应用程序与我的模块具有不同的运行时,则gpf/段故障时间。所以我有一个"release"成员,它执行自删除。

void foo::release(void) 
{
    delete this;
}

一切正常,但它确实要求模块的用户行为。

我的问题是:
  • 是否有可能阻止某人直接对我的对象发出删除(或将其重定向到从我的模块内存池中删除)?
  • 如果不是作为备份计划,是否有可能在我的对象中检测到这一点,所以我可以抛出一个断言来强制良好的行为?

E。G:

iFoo* foo = createFoo ();
foo->release();           // Allowed and expected
delete foo;               // Disallowed

在OP的评论中,@dave建议将纯接口中的析构函数声明为protected而不是public。这将完全阻止外部代码(即外部实现类)调用delete

例如:

class IFoo
{
protected:
    virtual ~IFoo() { }
public:
    virtual void release() = 0;
};
class Foo : public IFoo
{
public:
    void release() override
    {
        delete this;
    }
};
IFoo* createFoo()
{
    return new Foo();
}
int main()
{
    auto foo = createFoo();
    foo->release();  // Expected
    delete foo;      // Cannot access protected destructor of IFoo
    Return 0;
}

由于工厂函数只公开纯接口,如果实现类碰巧提供了公共析构函数,这种方法不会失效。如果Foo声明了一个公共析构函数,main仍然会出现编译错误,因为main不知道它实际上是在处理Foo

On Edit:这种方法只会让用户更难以删除资源——它并不能完全阻止它。(我不会删除这个答案,因为它可能仍然有用。)

如果你真的想阻止别人在你的对象上调用delete,那就禁止他们这样做——从你的工厂函数返回一个值类型。

值类型可以是实际对象的一个薄包装,可以提供指针语义,就像智能指针。

一个粗略的例子:

class IFoo
{
public:
    virtual ~IFoo() { }
    virtual void release() = 0;
};
class Foo : public IFoo
{
public:
    Foo() { }
    void release() override
    {
        delete this;
    }
};
// Value type with pointer semantics
template <class T>
class Undeletable
{
private:
    T* m_resource;
public:
    Undeletable(T* resource)
        : m_resource(resource)
    {
    }
    T* operator->()
    {
        return m_resource;
    }
};
// Old factory function
IFoo* createFoo()
{
    return new Foo();
}
// New factory function
Undeletable<IFoo> createSafeFoo()
{
    return Undeletable<IFoo>(createFoo());
}
int main()
{
    auto foo = createFoo();
    foo->release();  // Expected
    delete foo;      // Possible but DO NOT WANT
    auto safeFoo = createSafeFoo();
    safeFoo->release(); // Expected
    delete safeFoo;     // Compiler says NOPE
    return 0;
}

不幸的是,这只会混淆用户仍然可以删除资源的事实。例如:

delete safeFoo.operator->(); // Deletes the resource