如果我在我的库中使用new关键字(它与我的主应用程序构建方式不同),当我在我的主应用程序中使用delete删除它时,是否有可能出现崩溃/错误?
new
delete
vcirk6k61#
这要看情况而定。如果你说的是静态库,那么你很可能是对的--代码将在与主程序相同的上下文中运行,使用相同的C运行时库。这意味着new和delete将使用相同的堆。如果你说的是一个共享库(DLL),那么你可能就不太好了。在DLL中运行的代码可能使用不同的C运行时库,这意味着堆的布局将不同。DLL可能使用完全不同的堆。在DLL分配的指针上调用delete(在主程序中)(反之亦然)将导致(最好的情况下)立即崩溃或(最坏的情况下)内存损坏,需要一段时间才能跟踪。你有几个选择。第一个是使用“工厂方法”模式来创建和删除这些对象:
Foo *CreateFoo(); void DeleteFoo(Foo *p);
字符串这些不应该在头文件中实现。或者,你可以在对象上定义一个Destroy方法:
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方法,当对象的引用计数降为零时删除该对象。
Foo::Destroy
Release
ruoxqz4g2#
是的。特别是你会看到调试/发布堆不同的问题,如果你的库使用了placement new,或者任何自定义堆,你都会有问题。调试/发布问题是目前为止最常见的。
thigvfpy3#
是的,你会的。一个简单的解决方案是在你的库中提供可以从主应用程序调用的Create和Delete函数。Create函数将执行new并返回一个指针,该指针稍后被传递到Delete函数以进行删除。
z0qdvdin4#
这是一个我只在Windows上见过的问题。Unixish系统没有强制共享库链接到同一程序中同一库的不同版本的习惯,所有加载的符号都是全局可见的。这意味着如果一个对象在代码的一部分中被分配,而在另一部分中被删除,两者都使用相同的系统库来完成。我不得不说,Windows用它的各种C运行时DLL创建的这个问题对于C程序员来说真的很烦人,也很不自然。它有像strdup这样的函数,可以对字符串进行malloc,并期望程序员对其调用free()。但是在Windows上的你自己的库中做同样的事情,只需要等待爆炸。你也必须等待,因为它不会在开发过程中发生,而只会在你把编译好的DLL交给其他可怜的sap之后发生。
zbq4xfa05#
Old New Thing之前已经讨论过这个问题,他还列出了微软的主要解决方案。
jtw3ybtb6#
你说得很对,这确实是个问题,但对于大多数情况,有一个比其他答案(到目前为止)提出的更简单的解决方案。你可以继续自由地使用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边界。
6条答案
按热度按时间vcirk6k61#
这要看情况而定。如果你说的是静态库,那么你很可能是对的--代码将在与主程序相同的上下文中运行,使用相同的C运行时库。这意味着
new
和delete
将使用相同的堆。如果你说的是一个共享库(DLL),那么你可能就不太好了。在DLL中运行的代码可能使用不同的C运行时库,这意味着堆的布局将不同。DLL可能使用完全不同的堆。
在DLL分配的指针上调用
delete
(在主程序中)(反之亦然)将导致(最好的情况下)立即崩溃或(最坏的情况下)内存损坏,需要一段时间才能跟踪。你有几个选择。第一个是使用“工厂方法”模式来创建和删除这些对象:
字符串
这些不应该在头文件中实现。
或者,你可以在对象上定义一个
Destroy
方法:型
.同样,不要在头文件中实现它。你可以这样实现它:
型
请注意,Foo的析构函数是私有的,因此必须调用
Foo::Destroy
。Microsoft COM做了类似的事情,它定义了一个
Release
方法,当对象的引用计数降为零时删除该对象。ruoxqz4g2#
是的。特别是你会看到调试/发布堆不同的问题,如果你的库使用了placement new,或者任何自定义堆,你都会有问题。调试/发布问题是目前为止最常见的。
thigvfpy3#
是的,你会的。一个简单的解决方案是在你的库中提供可以从主应用程序调用的Create和Delete函数。Create函数将执行new并返回一个指针,该指针稍后被传递到Delete函数以进行删除。
z0qdvdin4#
这是一个我只在Windows上见过的问题。
Unixish系统没有强制共享库链接到同一程序中同一库的不同版本的习惯,所有加载的符号都是全局可见的。这意味着如果一个对象在代码的一部分中被分配,而在另一部分中被删除,两者都使用相同的系统库来完成。
我不得不说,Windows用它的各种C运行时DLL创建的这个问题对于C程序员来说真的很烦人,也很不自然。它有像strdup这样的函数,可以对字符串进行malloc,并期望程序员对其调用free()。但是在Windows上的你自己的库中做同样的事情,只需要等待爆炸。你也必须等待,因为它不会在开发过程中发生,而只会在你把编译好的DLL交给其他可怜的sap之后发生。
zbq4xfa05#
Old New Thing之前已经讨论过这个问题,他还列出了微软的主要解决方案。
jtw3ybtb6#
你说得很对,这确实是个问题,但对于大多数情况,有一个比其他答案(到目前为止)提出的更简单的解决方案。你可以继续自由地使用new和delete--你所需要做的就是为库中每个可能跨DLL边界使用的类重载new和delete。
就我个人而言,我只是定义了一个简单的类来提供所需的功能:
字符串
只要这四个成员函数都定义在同一个DLL中,那么从这个类派生的任何类都自动是“DLL安全的”-- new和delete可以在它们上正常使用,而不必担心DLL边界。