美文网首页
std::unique_ptr用法

std::unique_ptr用法

作者: dhz120 | 来源:发表于2020-04-17 09:29 被阅读0次

    一、原则

    使用std::unique_ptr管理具备专属所有权的资源

    二、常见用法

    std::unique_ptr的一个常见用法是在对象继承谱系中作为工厂函数的返回型别。这种继承谱系的工厂函数通常会在堆上分配一个对象并且返回一个指涉到它的指针,并当不在需要该对象时,由调用者负责删除之。

    三、示例(以下代码需要c++14支持

    #ifndef UNIQUEPTRDEMO_H
    #define UNIQUEPTRDEMO_H
    
    #include <iostream>
    #include <memory>
    
    namespace T17_NS {
    
    using namespace std;
    
    /*!
     * \brief The Investment class 基类
     */
    class Investment
    {
    public:
        virtual ~Investment() = default;
    
    public:
        virtual void doWork() = 0;
    };
    
    /*!
     * \brief The Stock class 派生类
     */
    class Stock : public Investment
    {
    public:
        virtual void doWork() override {
            cout << "Stock doWork....\n";
        }
    };
    
    /*!
     * \brief The Stock class 派生类
     */
    class Bond : public Investment
    {
    public:
        virtual void doWork() override {
            cout << "Bond doWork....\n";
        }
    };
    
    enum class InvestType {
        INVEST_TYPE_STOCK,
        INVEST_TYPE_BOND,
    };
    
    auto makeInvestment(InvestType type)
    {
        // 自定义析构器, 这里以lambda表达式的形式给出
        auto delInvmt = [](Investment *pInvestment) {
            // TODO 自定义析构时想干的事
            cout << "delInvmt called...." << endl;
            delete pInvestment;
        };
    
        // 待返回的指针, 初始化为空指针,并指定自定义析构器
        // decltype(delInvmt) 用于获取自定义析构器的类型
        unique_ptr<Investment, decltype(delInvmt)> pInv(nullptr, delInvmt);
    
        // 注意这里用reset来指定pInv获取从new产生的对象的所有权, 不能用=赋值
        switch (type)
        {
        case InvestType::INVEST_TYPE_STOCK:
            //pInv = new Stock; // error!! c++11禁止从裸指针到智能指针的隐式转换
            pInv.reset(new Stock);
            break;
        case InvestType::INVEST_TYPE_BOND:
            pInv.reset(new Bond);
            break;
        }
    
        // 返回智能指针
        return pInv;
    }
    
    void test()
    {
        // 测试工厂函数
        {
            // pInv出作用域后会自己析构
            auto pInv = makeInvestment(InvestType::INVEST_TYPE_STOCK);
            if (pInv)
            {
                pInv->doWork();
            }
        }
    
        cout << "----------------\n";
    
        // 测试move效果
        {
            auto pInv = makeInvestment(InvestType::INVEST_TYPE_BOND);
            auto pInv2 = move(pInv);
            cout << "after move pInv to pInv2 \n";
            if (!pInv)
            {
                cout << "pInv is empty \n";
            }
            if (pInv2)
            {
                cout << "pInv2 is valid \n";
                pInv2->doWork();
            }
        }
    
        cout << "----------------\n";
    
        // 测试unique_ptr向shared_ptr转换
        {
            shared_ptr<Investment> pInv = makeInvestment(InvestType::INVEST_TYPE_BOND);
            pInv->doWork();
        }
    }
    
    } // T17_NS
    
    #endif // UNIQUEPTRDEMO_H
    
    

    四、简单说明

    1. 工厂函数 auto makeInvestment(InvestType type);auto 表示让编译器自己去推导函数的返回值,即unique_ptr<Investment, decltype(delInvmt)>,这是c++14给出的新特性。
    2. 定义一个空的智能指针,并设置自定义析构器(注意:如果析构器只实施delete操作,则没必要自定义析构器)unique_ptr<Investment, decltype(delInvmt)> pInv(nullptr, delInvmt);。当使用自定义析构器时,需要指定析构器类型,这里用decltype(delInvmt)来获得lambda表达式的类型。
    3. 使用reset()函数来指定pInv获取从new产生的对象的所有权, 注意这里不能用=赋值,否则不能通过编译。因为C++11禁止从裸指针到智能指针的隐式型别转换。
    4. unique_ptr可以很高兴的转换为shared_ptr: shared_ptr<Investment> pInv = makeInvestment(InvestType::INVEST_TYPE_BOND), 注意pInv类型是shared_ptr<Investment>,并不需要指定出对应析构器的类型,但是依然会调用自定义的那个析构器。(如果pInv类型显示指定为unique_ptr<Investment>就会报错,需要指定自定义析构器类型)

    相关文章

      网友评论

          本文标题:std::unique_ptr用法

          本文链接:https://www.haomeiwen.com/subject/phgsvhtx.html