topazの遊び場

いろいろやってみる

そろそろC++やるぞパート19 ポインター ~ 簡易まとめ ~

そろそろC++やります

そろそろC++をやります。そろそろC++をやりたいからです。
何回やるかはわかりません。基礎を理解するまではやろうと思います。

という感じでやっています。

※ 初心者がメモレベルで記録するので、技術記事としてはお力になれないかもしれません。

内容

  • 今回は、今まで触れてきたポインタをまとめます。

ポインタ

ポインター」とも呼びますが、この記事では「ポインタ」の表記を使用します。

アドレス(メモリの位置)を持った変数のことを、ポインタ(またはポインタ変数)と呼びます。

生ポインタとスマートポインタ

C++では、いわゆる一般的なポインタである生ポインタと、リソースの管理を容易にしたスマートポインタが存在します。

生ポインタ
型名 *を用いて宣言します。

int *intPtr;
string *strPtr;

newなどで、メモリを割り当てます。

int *intPtr = new int(123);

ヒープ領域にメモリの確保するので、メモリの解放が必要です。

delete intPtr;

スマートポインタ
スマートポインタは、生ポインタと違いメモリの解放を自動で行ってくれます。スマートポインタは、3種類存在します。

  1. unique_ptr
  2. shared_ptr
  3. weak_ptr

それぞれが別々の特徴を持っているクラスです。
unique_ptrshared_ptrは、ヘルパー関数で初期化します。

auto up = make_unique<int>(234);
auto sp = make_shared<string>("Hello World");

weak_ptrshared_ptrから生成します。

weak_ptr wp = sp;

所有権

スマートポインタには、所有権という考えがあります。

所有権を普通のクラスを例にして考えてみます。以下の例では、unknownという名前のMyClassを、変数mcmc2が参照しています。

class MyClass
{
public:
    MyClass(string _name) : name(_name)
    {
    }
    string name;
};

int main()
{
    MyClass *mc = new MyClass("unknown");
    MyClass *mc2 = mc;

    return 0;
}

この参照を、所有として考えます。
つまり、いくつの変数が所有(参照)しているかです。

unique_ptr
unique_ptrは、所有権を一つしか持てません。
以下は変数upに最初に代入して、所有権(参照)はupが持っています。所有権は一つしかないので、他の変数にも代入するとエラーになります。

auto up = make_unique<int>(124);
auto up2 = up;    // コンパイルエラー

コードブロックを抜けて使われていないとメモリが解放されます。

shared_ptr shared_ptrは、所有権を複数持つことが可能です。
unique_ptrと異なり、他の変数に代入することができます。

auto up = make_shared<int>(124);
auto up2 = up;
auto up3 = up;  // 実行可能

所有権の数をカウントする、参照カウントが存在します。参照が増えた場合に増やして、コードブロックを抜けると減らします。

auto up = make_shared<int>(124);
cout << up.use_count() << endl; // 1
auto up2 = up;
cout << up.use_count() << endl; // 2
cout << up2.use_count() << endl; // 2
{
    auto up3 = up;
    cout << up.use_count() << endl; // 3
} // コードブロックを抜けるので一つ解放

cout << up.use_count() << endl; // 2

参照カウントが0になった時に、メモリの解放を行います。

weak_ptr
weak_ptrは弱いため、弱い所有権を持つことしかできません。shared_ptrから生成できますが、その時に参照カウントは増えません。

auto up = make_shared<int>(124);
cout << up.use_count() << endl;  // 1
weak_ptr wp = up;
cout << up.use_count() << endl;  // 1

これは、shared_ptrを使用して、循環参照が起こってしまう場合に主に使用します。

感想

今まで複数回にわたり触れてきて、これさえ覚えておけば、簡単に使用する分には問題なさそうなところをまとめました。(実戦ではもっと知識が必要そうですが)そこまで複雑ではなさそうというイメージです!

次回から、演算子について1から見ていこうと思います!