スマートポインタ(1)-std :: unique_ptrを

std :: unique_ptrを

std::unique_ptr、効率的かつスマートポインタ、ポインタのリソース管理が独占権を持っているように、ほとんどのプリミティブポインタ廃止されたC ++置き換えるために使用される標準的なC ++ 11、98により導入されたstd::auto_ptrスマートポインタを。これとは対照的に、std::unique_ptr利点は以下のとおりです。

  • 意味論より明確std::auto_ptrコピーを行う場合、実際に意味を移動するが、98 C ++で動きの意味を定義していない、時間の使用が直観であってもよいです。そしてstd::unique_ptr、移動操作のみ、Cの新しく定義された意味論++モバイル11を使用して、コピー操作は、その意味がより明確にすることを、禁止されています。
  • カスタムリムーバーを許可:としては、std::unique_ptrあなたがデバイスを削除する前に、着信カスタムの種類は、テンプレートパラメータに削除される指定する必要があるので、そのメンバ変数として削除されますstd::unique_ptr<T, D> up(nullptr, deleter)
  • 支持STLコンテナ:C ++ 98に、コンテナ要素は、このような«効果的なSTL»、容器内の要素に述べたように、コピーしなければならない必要std::sortエレメントが間隔から選択されるコピー(主要素をピボット)、その後、パーティションへのすべての要素。しかし、std::auto_ptrコピー操作は、セマンティクスを移動するために行われ、これはバグの原因となります。C ++ 11では、STLコンテナを移動セマンティクスをサポートし、std::unique_ptr唯一の移動操作は、コピー操作を削除し、提供および操作が動いているnoexceptいくつかのSTLコンテナの操作はコピーのいずれかが必要になります強い例外安全性を確保する必要があるため、これは重要である(中いずれかの操作を移動させるの異常な動作で)これは、コンテナのコピー操作は、そのような必要としないfillので、A機能をstd::unique_ptrコンテナ要素が正しいよう。

std :: unique_ptrをサイズ

デフォルトでは、std::unique_ptr元のポインタなどの大きさ:

#include <iostream>
#include <memory>

int main(int argc, const char* argv[]) {
    std::unique_ptr<int> upNum(new int);

    // 输出8(64位操作系统)
    std::cout << sizeof(upNum) << std::endl;

    return 0;
}

あなたは、削除の時間を追加すると、状況は、変更されたstd::unique_ptrオリジナルのポインタ型のサイズの大きさに相当する大きさをプラス削除しました:

#include <iostream>
#include <memory>

void deleter(int* pNum) {
    std::cout << "function deleter" << std::endl;
    delete pNum;
}

int main(int argc, const char* argv[]) {
    std::unique_ptr<int, decltype(&deleter)> upNum(new int, deleter);

    // 输出8+8=16(函数指针类型的大小也为8)
    std::cout << sizeof(upNum) << std::endl;

    return 0;
}

この状況は、最適化することができ、それはファンクタまたはデバイスが削除されたようにラムダ関数を使用することである、それは自動的に最適化離れ空模倣関数またはラムダ関数はステートレス(ステートレス)である場合、時間のクラスのメンバ変数として、クラス・タイプクラス空間がで占められています。

#include <iostream>
#include <memory>

int main(int argc, const char* argv[]) {
    auto deleter = [](int* pNum) {
        std::cout << "lambda deleter" << std::endl;
        delete pNum;
    };
    std::unique_ptr<int, decltype(deleter)> upNum(new int, deleter);

    // 输出8
    std::cout << sizeof(upNum) << std::endl;

    return 0;
}

使用シーンファクトリパターンの1-

#include <iostream>
#include <memory>

class Foo {
public:
    void greeting() noexcept {
        std::cout << "hi! i am foo" << std::endl;
    }
};

class Factory {
public:
    std::unique_ptr<Foo> createFoo() {
        return std::unique_ptr<Foo>(new Foo);
    }
};

int main(int argc, const char* argv[]) {
    auto foo = Factory().createFoo();

    // 输出"hi! i am foo"
    foo->greeting();

    return 0;
}

PIMPLモードは、2-シーンを使用して実装しました

PIMPL(実装へのポインタ)は、オブジェクト構造を指すポインタのみプライベートメンバーを残すプライベートImplを構造体自体へのすべてのメンバ変数によってカプセル化されます。
PIMPL利点モードである:1.結合モジュールを減らす2速くコンパイルを界面安定性を改善3

// Foo.h
#pragma once

#include <memory>
#include <string>

class Foo {
public:
    Foo();

    // 需要将~Foo的实现放入Foo.cpp中,避免出现delete imcomplete type错误
    ~Foo();

    // 1.定义了~Foo之后不会自动生成移动函数
    // 2.移动构造函数中因为会生成处理异常的代码,所以需要析构成员变量,也会造成delete imcomplete type问题,所以将实现放入Foo.cpp
    // 3.移动赋值函数中因为会先删除自己指向的Impl对象指针,也会造成delete imcomplete type问题,所以将实现放入Foo.cpp
    Foo(Foo&& rhs) noexcept;
    Foo& operator=(Foo&& rhs) noexcept;

    // 由于unique_ptr不支持复制,所以无法生成默认拷贝函数
    Foo(const Foo& rhs);
    Foo& operator=(const Foo& rhs);

    void setName(std::string name);
    const std::string& getName() const noexcept;

private:
    struct Impl;
    std::unique_ptr<Impl> m_upImpl;
};
// Foo.cpp
#include "Foo.h"
#include <string>

struct Foo::Impl {
    std::string name;
};

Foo::Foo() : m_upImpl(new Impl) {}

Foo::~Foo() = default;

Foo::Foo(Foo&& rhs) noexcept = default;
Foo& Foo::operator=(Foo&& rhs) noexcept = default;

Foo::Foo(const Foo& rhs) : m_upImpl(new Impl) {
    *m_upImpl = *rhs.m_upImpl;
}

Foo& Foo::operator=(const Foo& rhs) {
    *m_upImpl = *rhs.m_upImpl;
    return *this;
}

void Foo::setName(std::string name) {
    m_upImpl->name = name;
}

const std::string& Foo::getName() const noexcept {
    return m_upImpl->name;
}

std :: make_unique使用してみてください

使用しstd::make_unique作成するためにstd::unique_ptr、スマートポインタは次のような利点があります。

  • コードの重複を減らすコードから:std::unique_ptr<Foo> upFoo(new Foo);auto upFoo = std::make_unique<Foo>();fooはより多くのソフトウェアエンジニアリングの要件に沿ったものになりますmake_uniqueだけ書き込みを使用することを学ぶことができます。
  • 異常は、安全性を向上:実行順序の不確実性に起因する関数呼び出しのスマートポインタを構築する場合、そのようなのためのコードなどのリソースリークを引き起こすことがあります。

    #include <iostream>
    #include <memory>
    #include <exception>
    
    bool priority() {
        throw std::exception();
    
        return true;
    }
    
    void func(std::unique_ptr<int> upNum, bool flag) {
        if (flag) {
            std::cout << *upNum << std::endl;
        }
    }
    
    int main() {
        func(std::unique_ptr<int>(new int), priority());
    
        return 0;
    }
    ここでは、3つの手順を実行しますが、関数funcを呼び出します
    1. new int
    2. std::unique_ptr<int>コンストラクタ
    3. priority機能

    唯一の確実性は、ステップ1、ステップ2、順序のステップ3の前に起こるが、それの中央のステップ3ステップ1及び2は、メモリリークが発生する場合は、必ずしもではないです。しかし、あなたの使用があればmake_unique、この問題はありません。

しかし、std::make_uniqueその後、C ++ 14標準が導入された、C ++ 11の使用、この機能を実現する環境が必要です:

template<typename T, typename... Ts>
std::unique_ptr<T> make_unique(Ts&&... params)
{
return std::unique_ptr<T>(new T(std::forward<Ts>(params)...));
}
  • «効果的な近代的なC ++»からの材料

おすすめ

転載: www.cnblogs.com/HachikoT/p/12153553.html