C++如何删除指针并保证地址有效

3
我正在使用 Poco C++ 库,但是遇到了奇怪的问题。Poco 使用自己的共享指针类 SharedPtr 进行内部指针操作。在我的情况下,静态对象 Poco::SSLManager 有证书处理器对象的 SharedPtr 成员。当程序运行结束时,静态对象被删除并且我捕获到了分段错误。
使用 GDB 调试器,我看到核心转储并不理解问题所在。当删除 SharedPtr 对象(简单操作:delete pObj)时发生了分段错误,但对象具有有效地址,例如 - 0x8fcbed8
为什么删除具有有效地址的指针会导致分段错误?
这可能是因为对象在应用程序的 fork 副本中创建并在主进程中销毁的缘故吗?

在删除对象指针之前检查是否为 null 指针,并在删除操作后将其设置为 null。 - Reddy
1
SharedPtr通常具有ptr->Release()函数。请查看。 - Gasim
5
不要在调用“delete”之前检查是否为“null”,因为它被定义为在空指针上不执行任何操作。 - Puppy
在释放被调用之前,检查year ptr并将其设置为null。 - Reddy
4个回答

11

一个有效的地址只是一个可访问的地址。这并不意味着它适合删除。您只能从new返回的内容中删除。如果您没有使用new,则不能delete它。删除静态或自动对象是未定义行为 - 以及您可能从任何其他来源获得的对象,而不是new


3
而且,你不应该删除由智能指针所管理的任何内容。智能指针被称为"智能"是因为它们会自行处理删除操作。 - Nicol Bolas
新的当然是好的。但是在分叉过程中进行新的操作,并将对象存储在静态对象中(从共享库创建 - 因此),这会在父进程中销毁。我觉得这可能会产生冲突。 - Reddy
绝对绝对不能在进程之间删除。 - Puppy

0

正如其他人所说,指针看起来“好”像0x8fcbed8,并不意味着它是正确的指针。

事实上,如果您使用“delete”,指针将保持其值。但是您不应再使用它。(在删除后立即将其设置为NULL是一个好习惯,这样它就会在调试器中显示为空。)

如果您正在使用Linux进行开发,有一个工具可以帮助您找出问题。它是valgrind

valgrind  your_program  [args]

(只需在通常启动的命令前添加 "valgrind"。如果尚未安装,请安装 valgrind,因为它是广泛使用的工具,您的发行版上必须有一个包)

然后,当程序运行时,valgrind 将检查您的程序(稍微减慢一些速度),并在您删除不应该删除的内容时立即向您报告。(以及许多其他错误)


0

这是一个非常困难的问题,我并不完全理解问题,但我会尽力解释并提出我的解决方案。 该问题是特定于平台的,仅在使用gcc 4.5.5编译器和Poco库的Gentoo Linux上发生。

我有一个守护进程,用于处理不同请求的模块(插件)。模块和守护进程使用一个静态库,该静态库使用poco库。在静态库中有创建SSL连接的代码,并且作为结果创建SSL管理器。静态库链接到模块和守护进程。

在守护进程工作结束后,我遇到了描述在我的问题中的分段错误。我将静态库更改为共享库,问题消失了,没有分段错误。一切正常运行。

实际上,我不太理解它,但似乎这是Gentoo上gcc编译器的错误。在其他使用其他gcc的Linux上,所有内容都可以与静态库良好地配合使用。


Gentoo Linux使用gcc 4.5.5版本-错误使用了4.4.5版本。 - Reddy

0

你提到了使用 shared pointer。如果这个 delete 是 pObj 上的最后一个 delete,那么它可能是对象被删除的最后一次机会...因此,shared pointer 指向的对象将最终被销毁。在这种情况下,pObj 的 destructor 被调用,你可能会从那里得到 Seg Fault。

另一方面,根据 Poco 库使用的 shared pointer 实现方式,你可能正在错误地调用它的 delete。


Poco的SharedPtr类似于智能指针,使用内部原子计数器。我还检查了我的问题对象(InvalidCertificateHandler)的析构函数。它是一个简单的对象,没有父类,并且只有一个布尔变量。在析构函数中,我看到一些对静态对象SSLManager方法的调用,但是在注释后,应用程序的行为没有发生改变。 - Reddy
我认为你使用了错误的shared ptr,但很难猜测。请编辑您的帖子并添加一些代码,例如构造和操作Shared Ptr的行。 - Ioan Paul Pirau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接