如果我在我的库中使用new
关键字(其构建方式与我的主应用程序不同),当我在主应用程序中使用delete
删除它时,是否有可能获得崩溃/错误?
答案 0 :(得分:16)
这取决于。如果您正在谈论静态库,那么您可能会没问题 - 代码将在与主程序相同的上下文中运行,使用相同的C ++运行时库。这意味着new
和delete
将使用相同的堆。
如果您正在谈论共享库(DLL),那么您可能不会。 DLL中运行的代码可能使用不同的C ++运行时库,这意味着堆的布局将不同。 DLL可能完全使用不同的堆。
在DLL分配的指针上调用delete
(在主程序中)(反之亦然)将导致(最多)立即崩溃或(最坏情况下)内存损坏,这需要一段时间追查。
你有几个选择。第一种是使用“工厂方法”模式来创建和删除这些对象:
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
方法,该方法在引用计数降至零时删除该对象。
答案 1 :(得分:10)
答案 2 :(得分:6)
是的,你会的。一个简单的解决方案是在库中提供可以从主应用程序调用的创建和删除功能。 Create函数将执行new并返回一个指针,该指针稍后将被传递到Delete函数以进行删除。
答案 3 :(得分:5)
这是我在Windows上看到的一个问题。
Unixish系统没有习惯强制共享库链接到同一程序中同一个库的不同版本,并且所有加载的符号都是全局可见的。这意味着如果一个对象在一部分代码中分配并在另一部分中删除,则两者都使用相同的系统库来执行此操作。
我不得不说,Windows使用各种C运行时DLL创建的这个问题对于C程序员来说真的很烦人且不自然。看看C库;它具有strdup等函数,malloc字符串并期望程序员在其上调用free()。但是在Windows上自己的库中做同样的事情,等待爆炸。你也必须等待,因为它不会在开发过程中发生,而是在你将已编译的DLL提供给其他一些糟糕的sap之后。
答案 4 :(得分:3)
Old New Thing之前已经涵盖了这一点。他还列出了微软的主要解决方案。
答案 5 :(得分:1)
你说那里有一个问题是对的,但是对于大多数情况来说,有一个比其他答案(到目前为止)提出的更简单的解决方案。您可以继续使用new并自由删除 - 您需要做的就是对库中可能跨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边界。