线程执行std::make_shared时,其他线程会导致其创建的对象泄漏吗?
从《Effective Modern C++》Item 21的内容可知,new搭配std::shared_ptr的写法存在对象泄漏风险,比如这段代码:
processWidget(std::shared_ptr<Widget>(new Widget), computePriority());
C++编译器对函数参数的求值顺序没有强制规定,可能出现这样的执行顺序:先执行new Widget完成对象分配,接着调用computePriority(),如果这个函数抛出异常,std::shared_ptr的构造函数还没来得及执行——此时已创建的Widget没有被智能指针接管,直接造成内存泄漏。
换成std::make_shared就能规避这个问题:
processWidget(std::make_shared<Widget>(), computePriority());
std::make_shared的内部逻辑是在同一个连续的执行步骤里完成对象分配和std::shared_ptr的构造,只要对象成功分配,立刻就被智能指针持有,哪怕后续computePriority()抛出异常,智能指针销毁时也会自动释放对象,不会出现泄漏。
针对你朋友的疑问——多线程下std::make_shared会不会出现类似泄漏?答案是不会,原因如下:
- 线程的执行流程是独立的,线程
t1在执行std::make_shared<Widget>()的过程中,其他线程的代码不可能插入到t1内部的指令序列中。std::make_shared里的对象分配和智能指针构造这两步,在t1内部是连续执行的,不存在被其他线程打断的可能。 - 多个线程各自调用
std::make_shared时,每个线程都会独立分配属于自己的Widget对象,各自的std::shared_ptr只管理自己线程创建的对象,互相没有关联,不会因为线程干扰导致对象泄漏。
唯一需要注意的是,如果Widget的构造函数本身存在线程不安全的操作(比如访问未加锁的全局资源),那会引发其他问题,但这属于Widget自身的线程安全缺陷,和std::make_shared的泄漏风险无关——哪怕单线程下写有问题的构造函数,一样会出问题。
内容的提问来源于stack exchange,提问作者Enlico
相关产品推荐
相关产品推荐

