这会导致 DLL 的不同运行时出现问题吗?

发布于 2024-10-11 06:03:00 字数 845 浏览 1 评论 0原文

我的 gui 应用程序支持多态定时事件,这意味着用户调用 new,而 gui 调用删除。如果运行时不兼容,这可能会产生问题。

所以我被告知建议的解决方案是这样的:

class base;

class Deallocator {
    void operator()(base* ptr) 
    {
        delete ptr;
    }
}

class base {
public:
base(Deallocator dealloc) 
{
    m_deleteFunc = dealloc;
}
~base() 
{
    m_deleteFunc(this);
}

private:
Deallocator m_deleteFunc;
}

int main
{
    Deallocator deletefunc;

    base baseObj(deletefunc);
}

虽然这是一个很好的解决方案,但它确实要求用户创建一个我不想要的 Deallocator 对象。然而,我想知道是否为每个派生类提供了一个 Deallocator:例如,

class derived : public base
{
  Deallocator dealloc;
public:
  Derived() : base(dealloc);
{
}
};

我认为这仍然不起作用。约束条件是: addTimedEvent() 函数是 Widget 类的一部分,该类也在 dll 中,但由用户实例化。另一个限制是一些从 Widget 派生的类使用它们自己的定时事件类调用此函数。

考虑到“调用 new 的人必须调用 delete”,考虑到这些限制,什么可以起作用?

谢谢

My gui application supports polymorphic timed events so that means that the user calls new, and the gui calls delete. This can create a problem if the runtimes are incompatible.

So I was told a proposed solution would be this:

class base;

class Deallocator {
    void operator()(base* ptr) 
    {
        delete ptr;
    }
}

class base {
public:
base(Deallocator dealloc) 
{
    m_deleteFunc = dealloc;
}
~base() 
{
    m_deleteFunc(this);
}

private:
Deallocator m_deleteFunc;
}

int main
{
    Deallocator deletefunc;

    base baseObj(deletefunc);
}

While this is a good solution, it does demand that the user create a Deallocator object which I do not want. I was however wondering if I provided a Deallocator to each derived class: eg

class derived : public base
{
  Deallocator dealloc;
public:
  Derived() : base(dealloc);
{
}
};

I think this still does not work though. The constraint is that:
The addTimedEvent() function is part of the Widget class which is also in the dll, but it is instanced by the user. The other constraint is that some classes which derive from Widget call this function with their own timed event classes.

Given that "he who called new must call delete" what could work given these constraints?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

小嗷兮 2024-10-18 06:03:00

我建议您研究 COM 引用计数范例(AddRef 和 Release)。这允许更灵活的生命周期并保证使用正确的释放器,因为对象会删除自身。

请注意,如果您跨 DLL 边界共享类对象,则可能会遇到比仅使用相同分配器更大的问题。需要考虑整个单一定义规则,以及编译器之间不同的调用约定、数据布局和名称修改方案。因此,如果您想要一个可重用的库,您确实需要采用 COM 方式来执行操作,包括引用计数、自删除和仅包含纯虚函数的接口。无论您构建真正的 COM 对象还是您自己的类 COM 系统,都取决于您的其他需求。

I suggest that you study the COM reference-counting paradigm (AddRef and Release). This allows more flexible lifetime and guarantees that the correct deallocator is used, because the object deletes itself.

Please note that if you're sharing class objects across DLL boundaries, you could have much bigger problems that just using the same allocator. There's the whole one-definition-rule to account for, and calling conventions, data layout, and name mangling schemes that differ between compilers. So if you want a reusable library, you really need to adopt the COM way of doing things with reference counting, self-deletion, and an interface containing only pure virtual functions. Whether you build real COM objects or your own COM-like system would depend on your other requirements.

口干舌燥 2024-10-18 06:03:00

首先想到的是给基类一个虚拟(抽象?)SelfDestruct 方法。假设 DLL 的使用者传递了一个他自己派生的类,他将知道如何释放它。

如果他能通过你写的课程,那么你就会遇到更多问题。我建议禁止分配此类类,并提供一个静态方法来使用您自己的分配器分配它们。

我不确定我是否已经清楚地解释了我的想法......如果没有,请询​​问,我稍后会提供代码。

The first thing that comes to mind is to give the base class a virtual (abstract?) SelfDestruct method. Assuming that the consumer of your DLL passes a class he derived himself, he will know how to deallocate it.

If he can pass classes which you have written, then you've got more problems. I suggest disallowing allocating such classes and providing a static method for allocating them with your own allocator.

I'm not sure if I've explained my idea very clearly... if not, please ask, I'll provide code later.

唔猫 2024-10-18 06:03:00

在给定的约束下,可以将删除器函数指针与每个 TimedEvent 相关联,其中两者都被指定为 addTimedEvent 的参数。
为了减轻客户端创建自定义删除器函数的负担,您可以在小部件类的标头中提供内联删除器函数作为匿名命名空间的成员

例如:

// Widget header

class base;
namespace {
  inline void default_deleter(base* p) 
  { 
    delete p; 
  }
}

class Widget
{
public:
  addTimedEvent(base* event, void(*deleter)(base*));
};

内联函数的优点是它将在客户端代码的上下文中编译,因此delete还将使用兼容的释放器作为客户端用于分配事件。

编辑:使删除器函数成为匿名命名空间的成员。这是避免 ODR 违规所必需的。
如果没有命名空间,您将获得两个具有相同外部名称的函数 default_deleter(因此就链接器而言它们是相同的),但具有不同的语义,因为它们引用不同的释放器。< br>
使用匿名命名空间,default_deleter 的所有实例都成为链接器的单独实体。这有一个(不幸的)副作用,即您不能再使用该函数作为 addTimedEvent 的默认参数。

What could work with the given constraints is that you associate a deleter function-pointer with each TimedEvent, where both are specified as arguments to addTimedEvent.
To relieve the burden of the client to create a custom deleter function, you can provide an inline deleter function as a member of the anonymous namespace in the header of your widget class.

For example:

// Widget header

class base;
namespace {
  inline void default_deleter(base* p) 
  { 
    delete p; 
  }
}

class Widget
{
public:
  addTimedEvent(base* event, void(*deleter)(base*));
};

The advantage of the inline function is that it will be compiled in the context of the client code, so delete will also use a compatible deallocator as the client used to allocate the event.

Edit: Made the deleter function a member of the anonymous namespace. This is needed to avoid ODR violations.
Without the namespace, you get two functions default_deleter that have the same external name (so they are the same as far as the linker is concerned), but with different semantics, because they refer to different deallocators.
With the anonymous namespace, all instances of default_deleter become separate entities for the linker. This has the (unfortunate) side-effect that you can no longer use the function as a default argument to addTimedEvent.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文