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だけ書き込みを使用することを学ぶことができます。 異常は、安全性を向上:実行順序の不確実性に起因する関数呼び出しのスマートポインタを構築する場合、そのようなのためのコードなどのリソースリークを引き起こすことがあります。
ここでは、3つの手順を実行しますが、関数funcを呼び出します#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; }
new int
std::unique_ptr<int>
コンストラクタ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 ++»からの材料