You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

是否误解shared_ptr默认参数作用域?析构器未触发问题咨询

为啥你的shared_ptr自定义析构函数没触发?

先看看你的代码:

#include <iostream>
#include <memory>
using Foo = int;
using FooPtr = std::shared_ptr<Foo>;
FooPtr makeFoo() {
    FooPtr f{ new Foo(), [](Foo* ptr) { delete ptr; std::cerr << "!\n"; } };
    return f;
}
void bar(FooPtr p = {}) {
    p = makeFoo();
}
int main() {
    bar();
}

预期输出: !
实际情况: 无输出(析构器未被调用)

你本来以为bar()执行完返回时,shared_ptr会销毁并触发自定义删除器输出!,但在CentOS7的GCC4.8.5上没看到预期结果,对吧?


问题根源:GCC 4.8.x的shared_ptr默认参数bug

这是GCC 4.8系列版本的一个已知缺陷:当你把shared_ptr作为函数的默认参数(比如这里的FooPtr p = {}),然后在函数内部给这个参数赋值时,编译器生成的代码会出问题——赋值后的shared_ptr在函数退出时没有正确触发析构逻辑,包括你写的自定义删除器。

这个bug在GCC 5及以后的版本里已经被修复了,如果你能升级编译器,问题应该直接就解决了。


针对GCC4.8.x的临时解决办法

如果暂时没法升级编译器,给你几个可行的修改方案:

方案1:用函数重载替代默认参数

把带参数和不带参数的情况分开写,绕开默认参数的坑:

void bar(FooPtr p) {
    p = makeFoo();
}

void bar() {
    FooPtr p;
    p = makeFoo();
}

方案2:在函数内显式重置指针

强制让shared_ptr在函数结束前触发析构:

void bar(FooPtr p = {}) {
    p = makeFoo();
    // 显式重置,确保删除器被调用
    p.reset();
}

方案3:直接用局部变量(最推荐)

其实你这个场景根本不需要用默认参数,直接在函数里声明局部的shared_ptr就行,写法更清晰,还能避开bug:

void bar() {
    FooPtr p = makeFoo();
}

这样修改后,再运行代码应该就能看到预期的!输出了。

内容的提问来源于stack exchange,提问作者Lightness Races in Orbit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:49:42