重构代码以使用 Boost 共享指针

Refactoring code to use Boost shared pointers

本文关键字:Boost 共享 指针 代码 重构      更新时间:2023-10-16

我使用普通指针编写了一个项目,现在我厌倦了手动内存管理。

在重构过程中可以预见到哪些问题?

到目前为止,我已经花了一个小时将X*替换为shared_ptr<X>,用于我想要自动管理内存的类型。然后我把dynamic_cast改成了dynamic_pointer_cast.我仍然看到更多的错误(与NULL相比,this传递给函数(。

我知道这个问题有点模糊和主观,但我认为我可以从已经这样做的人的经验中受益。

有什么陷阱吗?

尽管在

任何地方都很容易使用boost::shared_pointer,但您应该根据所有权语义使用正确的智能指针。

在大多数情况下,默认情况下需要使用std::unique_ptr,除非所有权在多个对象实例之间共享。

如果您遇到周期性所有权问题,您可以使用 boost::weak_ptr 来分解周期。

还要记住,在传递shared_ptr时,出于性能原因(避免原子增量(,您应该始终通过 const 引用传递它们,除非您真的想将所有权授予不同的实体。

有什么陷阱吗?

是的,根据墨菲定律,如果你盲目地用shared_ptr替换每个指针,结果会发现这不是你想要的,你将在接下来的 6 个月里寻找你引入的错误。

在重构过程中可以预见到哪些问题?

内存

管理效率低下、未使用的资源存储时间超过必要时间、内存泄漏(循环引用(、无效引用计数(分配给多个不同shared_pointers的同一指针(。

不要盲目地用shared_ptr替换所有东西。仔细调查程序结构,并确保需要shread_ptr并且它准确地代表了您想要的。

此外,请确保使用支持简单分支(git 或 mercurial(的版本控制,因此当您破坏某些内容时,您可以恢复到以前的状态或运行类似于"git bisect"的内容来定位问题。

显然,您需要用shared_ptr替换 X*

错。这取决于上下文。如果你有一个指向某个数组中间的指针(比如像素数据操作(,那么你将无法用shared_ptr替换它(也不需要(。仅当需要确保对象的自动释放时,才需要使用shared_ptr。对象的自动释放并不总是您想要的。

如果你想

坚持使用boost,你应该考虑你想要一个boost::shared_ptr还是一个boost::scoped_ptr。shared_ptr是在类之间共享的资源,而scoped_ptr听起来更像您想要的(至少在某些地方(。当内存超出范围时,scoped_ptr将自动删除内存。

将shared_ptr传递给函数时要小心。shared_ptr的一般规则是按值传递,以便创建副本。如果通过引用传递它,则指针的引用计数将不会递增。在这种情况下,您最终可能会删除要保持活动状态的一段内存。

但是,在某些情况下,您可能希望通过引用传递shared_ptr。也就是说,如果您希望在不同的函数中分配内存。在这种情况下,只需确保调用方在其调用的函数的生存期内仍持有指针。

void allocPtr( boost::shared_ptr< int >& ptrByRef )
{
    ptrByRef.reset( new int );
    *ptrByRef = 3;
}
int main()
{
    boost::shared_ptr< int >& myPointer;
    // I want a function to alloc the memory for this pointer.
    allocPtr( myPointer ); // I must be careful that I still hold the pointer
                           // when the function terminates
    std::cout << *ptrByRef << std::endl;
}

我列出了所涉及的步骤/问题。他们为我工作,但我不能保证他们是 100% 正确的

0( 检查是否存在循环共享指针。如果是这样,这会导致内存泄漏吗?幸运的是,我的情况不需要打破循环,因为如果我有一个循环,循环中的对象是有用的,不应该被破坏。使用弱指针打破循环

1(您需要将"大多数"X*替换为shared_ptr<X>。shared_ptr(仅?(在每次动态分配 X 后立即创建。在所有其他时候,它是复制构造的,或者用空指针构造的(以指示 NULL(。为了安全起见(但效率低下(,请仅通过引用传递这些shared_ptrs。无论如何,您可能从未通过引用传递以 => 开头的指针,无需进行其他更改

2(您可能在某些地方使用了dynamic_cast<X*>(y)。将其替换为 dynamic_pointer_cast<X>(y)

3(无论你传递NULL(例如,发出计算失败的信号(,都要传递一个空的共享指针。

4( 删除相关类型的所有删除语句

5( 让你的基类 B 继承自 enable_shared_from_this<B> .然后无论你经过哪里this,通过,shared_from_this().如果函数需要派生类型,则可能必须执行静态强制转换。请记住,当您致电shared_from_this()时,某些shared_ptr必须已经拥有this。特别是,不要在类的构造函数中调用shared_from_this()

我相信可以半自动化这个过程以获得语义等效但不一定非常有效的代码。程序员可能只需要推理循环引用(如果有的话(。

我在许多步骤中使用了正则表达式。大约花了3-4个小时。到目前为止,代码已编译并正确执行。

有一个工具可以尝试自动转换为智能指针。我从来没有尝试过。以下是以下论文摘要的引述:http://www.cs.rutgers.edu/~santosh.nagarakatte/papers/ironclad-oopsla2013.pdf

为了强制实施难以静态检查的安全属性, 铁定C++通过模板化的"智能"应用动态检查 指针"类。 使用半自动重构工具,我们移植了 近 50K 行代码到铁定C++