C++ std::make_shared用途

1. 概述

Effective Modern C++中指出,在给智能指针std::shared_ptr初始化时,优先考虑使用std::make_shared,而非直接使用new。

2. 为什么优先考虑使用std::make_shared

总结有以下几点原因。

2.1 代码更简洁

看如下示例代码:

class TestObj {};

//使用make函数
auto ptr(std::make_shared<TestObj>());

//不使用make函数
std::shared_ptr<TestObj> ptr2(new TestObj());

从示例可以看出,不使用make_shared时,需要写2次类型名称TestObj。而使用make_shared代码更简洁。

引用书中原文:重复写类型和软件工程里面一个关键原则相冲突:应该避免重复代码。源代码中的重复增加了编译的时间,会导致目标代码冗余,并且通常会让代码库使用更加困难。它经常演变成不一致的代码,而代码库中的不一致常常导致bug。此外,打两次字比一次更费力,而且没人不喜欢少打字吧?

这只是一方面原因,但这不是重点,下面的问题才是根本原因。

2.2 使用new容易造成资源泄露

看如下示例代码:

class TestObj {};

int Compute() {
    if (xxx) {
        // 有可能抛异常
        throw Exception();
    }
    return 0;
};

void DoSomething(std::shared_ptr<TestObj> ptr, int n) {}

DoSomething(std::shared_ptr<TestObj>(new TestObj()), Compute());

DoSomething接受2个参数,但是调用DoSomething时,编译器不能保证先构造完第1个参数,再构造第2个参数。假如编译器生成的代码按如下顺序执行:

  1. new TestObj()
  2. Compute()
  3. std::shared_ptr(第一步new的内存)

一旦第2步Compute函数抛异常,第一步new的内存将无法释放,造成泄露。

使用std::make_shared就没有这个问题:

DoSomething(std::make_shared<TestObj>(), Compute());

一定要用new的话,将DoSomething的参数先初始化好再传入也可以:

auto ptr = std::shared_ptr<TestObj>(new TestObj());
DoSomething(ptr, Compute());

上述代码,智能指针出现了一次多余的值拷贝,如果追求极致性能,可以使用std::move:

// 使用std::move,避免值拷贝
DoSomething(std::move(ptr), Compute());

关于std::move,涉及到左值、右值等概念,下次再写。

建站  ·  开发  ·  读书  ·  教程
↑长按或扫码关注“编程之海”公众号↑
↑长按或扫码关注“编程之海”公众号↑
编程之海 版权所有丨如未注明,均为原创丨转载请注明转自:https://codingsea.com/c-stdmake_shared%e7%94%a8%e9%80%94/
0 0 投票数
文章评分
订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论

0

0

230

0
希望看到您的想法,请您发表评论x