2017-02-22 104 views
1

它是安全的呼吁删除一个基类指针通过动态加载库分配的堆对象?该lib和客户端都由相同的编译器(GCC)构建。安全++

+0

(加载的lib通过以通常的方式调用“new”来分配它 - 不使用就地提供给我的内存地址的“new”,或类似的东西)。 –

+1

看起来像这个问题来自用法的MS东西。不,的Linux/Unix系统中实现共享库正确放在第一位,而不是废话从MS – Slava

+0

如果我能找到一个官方十岁上下的基准说为多,这会解决我的问题。 :) –

回答

0

是的,如果它被分配了new,并且库(或任何其他代码)在删除后不尝试使用该对象。

+1

析构函数必须声明为“虚拟”。 – mch

+0

@mch你能详细说明原因吗? – emlai

+0

如果基类的析构函数不是虚拟的,当删除基指针时,它不会调用派生类的析构函数。 – mch

4

它是安全的delete指针当且仅当

  • 基类的析构函数是虚拟的。
  • 指针被new返回(不new[],不malloc,不mmap,...)
  • 您是指针的唯一所有者。换句话说:如果没有其他代码片段(在dll内或在dll外)将要使用或销毁尖锐的对象。

至于标准而言,该库必须使用相同版本的运行时库定义配置功能的链接。相同的要求适用于静态链接在一起的单独对象文件。在技​​术上,内存分配函数的多种不同实现违反了一个定义规则,但是用标准库扩展语言的C++实现可能会扩展语言以允许这些函数的多种不同实现。如果这是您所使用的执行的话,那么它可能不会是安全的解除分配共享库分配的内存,除非你能证明同样的版本中使用的库以及删除的对象的代码两者。


无论是安全与否,这是一个坏主意,以提供返回的资源(如动态内存),其采用释放这些资源照顾的API,而不是API。

+0

错误,析构函数不一定是虚拟的,以便删除是安全的。如果你想要调用任何派生类的析构函数,它只是虚拟的。 – emlai

+1

@tuple_cat *“如果要删除的对象的静态类型与其动态类型不同,则静态类型应为要删除的对象的动态类型的基类,并且**静态类型应具有一个虚拟的析构函数或行为是未定义的**。“*所以说标准。 – user2079303

+0

@tuple错误 - 标准说如果基本析构函数不是虚拟的,则通过基指针删除派生对象是未定义的行为。该标准没有说明在这种情况下可能或不可能调用哪些析构函数。 –

1

这取决于编译器和标志是动态库编译时使用的版本。

图书馆对new的调用会从库控制的堆中抓取对象。

您对delete的呼叫将对象放回由可执行文件控制的堆。

这可能是也可能不是由同一库管理的相同的堆。

安全的方法是将delete包装在库调用中,如fopen/fclose。

+0

听到关于这个谣言是什么促使我的问题,实际上。我很想知道这种双堆行为是否仅由隐蔽的操作系统完成,或者是否主流Linux发行版这样做。 –

+0

我在动态库被编译为旧版本的g ++时看到了它。这是很久以前,现在可能有更好的解决方案。在任何情况下,请考虑使用g ++编译的可执行文件以及使用英特尔编译器编译的库:) – Arkadiy

+0

在Unix/Linux世界中没有“库控制的堆”这样的事情。正如OP问题所说的gcc,这可能意味着Linux,这不是一个问题。 – Slava