std::unique_ptr は、<memory> ヘッダで提供されるスマートポインタである。
1つのオブジェクトの所有権をただ1つだけ持つ。
コピーはできず、ムーブによって所有権を別の std::unique_ptr へ移せる。
基本
通常は、共有しない動的オブジェクトの管理に使う。
#include <iostream>
#include <memory>
class Resource
{
public:
Resource() { std::cout << "Resource acquired\n"; }
~Resource() { std::cout << "Resource destroyed\n"; }
};
int main()
{
std::unique_ptr<Resource> ptr { new Resource{} };
}スコープを抜けると、ptr のデストラクタによって管理対象も自動で破棄される。
make_unique
std::unique_ptr を作るときは、通常 std::make_unique を使う。
#include <memory>
int main()
{
auto ptr { std::make_unique<int>(5) };
}std::make_unique を使う理由は次のとおりである。
newを直接書かずに済むので簡潔である- 一時的な生ポインタを露出させずに書ける
std::unique_ptrに所有させたいことがその場で分かりやすい
そのため、特別な理由がなければ std::make_unique を使うほうが自然である。
アクセス
std::unique_ptr は * と -> で管理対象にアクセスできる。
#include <iostream>
#include <memory>
class Resource
{
public:
void say() const
{
std::cout << "hello\n";
}
};
int main()
{
auto ptr { std::make_unique<Resource>() };
if (ptr)
ptr->say();
}生ポインタが必要な場面では get() で取り出せる。
ただし、get() で得たポインタは所有権を持たない。
所有権の移動
std::unique_ptr はコピーできないので、別の std::unique_ptr に渡すときは通常 std::move を使う。
#include <memory>
#include <utility>
int main()
{
auto p1 { std::make_unique<int>(5) };
auto p2 { std::move(p1) };
}このあと p1 は空になり、所有権は p2 に移る。
関数とのやりとり
関数が所有権を受け取るなら、std::unique_ptr を値渡しする。
#include <memory>
class Resource {};
void takeOwnership(std::unique_ptr<Resource> res);単に使うだけなら、管理対象への参照やポインタを渡すほうが自然なことが多い。
#include <memory>
class Resource {};
void useResource(const Resource& res);また、std::unique_ptr は関数から値で安全に返せる。
#include <memory>
class Resource {};
std::unique_ptr<Resource> createResource()
{
return std::make_unique<Resource>();
}このように返すと、所有権を安全に呼び出し側へ渡せる。
補足
- 配列用の
std::unique_ptr<T[]>もある - まず所有者として
std::unique_ptrを考えるのが、現代の C++ では自然なことが多い