04 March 2023

C++ 核心指南目录

“Do not pass a pointer or reference obtained from an aliased smart pointer”

理由

违背此规则是导致引用计数丢失的首要原因。你会遇到悬挂指针问题。函数调用链中应该首选原始指针或引用。在调用链顶层,从智能指针获取原始指针或引用。智能指针用来记录对象是否存活。同时,你得保证在函数调用链中,智能指针不会不小心重置或重新赋值。

注意

有时候,你需要保存智能指针的一份本地副本,这个副本可以确保在函数调用期间对象不会删除。

例子

// global (static or heap), or aliased local ...
shared_ptr<widget> g_p = ...;

void f(widget& w)
{
    g();
    use(w);  // A
}

void g()
{
    g_p = ...; // oops, if this was the last shared_ptr to that widget, destroys the widget
}

以下代码有问题:

void my_code()
{
    // BAD: passing pointer or reference obtained from a non-local smart pointer
    //      that could be inadvertently reset somewhere inside f or its callees
    f(*g_p);

    // BAD: same reason, just passing it as a "this" pointer
    g_p->func();
}

修改方法也很简单,只要本地复制一份指针,在调用树中保持引用计数。

void my_code()
{
    // cheap: 1 increment covers this entire function and all the call trees below us
    auto pin = g_p;

    // GOOD: passing pointer or reference obtained from a local unaliased smart pointer
    f(*pin);

    // GOOD: same reason
    pin->func();
}

强化

  • 警告:从非局部的一个智能指针获取的指针/引用或者局部但可能是个别名的指针,用在了函数调用中。如果智能指针是一个共享指针,那么建议获取一份局部副本,并从那个副本获取指针或引用来使用。