15

如果我new在我的库中使用关键字(它的构建方式与我的主应用程序不同),当我在我的主应用程序中使用 删除它时delete,是否有可能出现崩溃/错误?

4

6 回答 6

19

这取决于。如果您谈论的是静态库,那么您可能会没事——代码将在与主程序相同的上下文中运行,使用相同的 C++ 运行时库。这意味着new并且delete将使用相同的堆。

如果您谈论的是共享库(DLL),那么您可能不会好。在 DLL 中运行的代码可能使用不同的 C++ 运行时库,这意味着堆的布局会有所不同。DLL 可能完全使用不同的堆。

调用delete(在主程序中)由 DLL 分配的指针(反之亦然)将导致(最好的​​情况)立即崩溃或(最坏的情况)需要一段时间才能追踪的内存损坏。

你有几个选择。第一种是使用“工厂方法”模式来创建和删除这些对象:

Foo *CreateFoo();
void DeleteFoo(Foo *p);

这些应该在头文件中实现。

或者,您可以Destroy在对象上定义一个方法:

class Foo
{
    ~Foo();

public:
    virtual void Destroy();
};

...再次,不要在头文件中实现它。你会这样实现它:

void Foo::Destroy()
{
    delete this;
    // don't do anything that accesses this object past this point.
}

请注意, Foo 的析构函数是私有的,因此您必须调用Foo::Destroy.

Microsoft COM 做了类似的事情,它定义了一个Release方法,当对象的引用计数降至零时删除该对象。

于 2009-01-14T15:51:21.553 回答
11

是的。特别是,您会看到调试/发布堆不同的问题,如果您的库使用新放置或任何自定义堆,您也会遇到问题。调试/发布问题是迄今为止最常见的问题。

于 2009-01-14T14:40:44.783 回答
6

是的你将会。一个简单的解决方案是在您的库中提供可从主应用程序调用的 Create 和 Delete 函数。Create 函数将执行 new 并返回一个指针,该指针稍后将传递给 Delete 函数进行删除。

于 2009-01-14T14:54:29.857 回答
5

这是我只在 Windows 上看到的问题。

Unixish 系统不习惯强制共享库链接到同一程序中同一库的不同版本,并且所有加载的符号都是全局可见的。这意味着如果一个对象在代码的一部分中分配并在另一部分中删除,则两者都使用相同的系统库来执行此操作。

我不得不说,Windows 使用其各种 C 运行时 DLL 创建的这个问题对于 C 程序员来说确实很烦人且不自然。查看 C 库;它具有类似 strdup 的函数,可以对字符串进行 malloc 并期望程序员对其调用 free() 。但是在你自己的 Windows 库中做同样的事情,然后等待爆炸。您也必须等待,因为它不会在开发过程中发生,但只有在您将已编译的 DLL 提供给其他一些可怜的 sap 之后才会发生。

于 2009-01-14T16:39:18.133 回答
4

Old New Thing之前已经介绍过这一点。他还列出了微软的主要解决方案。

于 2009-01-14T21:31:16.407 回答
2

你说得对,那里有问题,但在大多数情况下,有一个比其他答案(到目前为止)提出的更简单的解决方案。您可以继续自由地使用 new 和 delete —— 您需要做的就是为库中可能跨 DLL 边界使用的每个类重载 new 和 delete。

就个人而言,我只是定义了一个简单的类来提供所需的功能:

class NewDelete
{
    public:
        void *operator new (size_t size);
        void operator delete (void *memory);
        void *operator new (size_t size, void *ptr);
        void operator delete (void *memory, void *ptr);
};

只要这四个成员函数都定义在同一个 DLL 中,那么从这个类派生的任何类都自动是“DLL 安全的”——new 和 delete 可以在它们上正常使用,而不必担心 DLL 边界。

于 2009-01-14T16:22:53.440 回答