禁止/重定向C ++删除?

时间:2014-03-26 00:05:49

标签: c++ destructor delete-operator

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

由于分配在模块内部进行,因此删除也需要,因为如果应用程序对我的模块有不同的运行时间,则为gpf / segfault时间。所以我有一个“发布”成员,执行自我删除。

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

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

我的问题是:

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

E.G:

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

2 个答案:

答案 0 :(得分:1)

在对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

答案 1 :(得分:0)

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