C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++のポインタ、スマートポインタ、shared_ptrを徹底解説

ポインタ(Pointer)とは

ポインタは、変数のメモリアドレスを格納するための特殊な変数です。C++では、ポインタを利用することで、変数が配置されているメモリ上の場所を直接扱うことができます。

構文

Type *pointer;

初期化

Type *pointer;
pointer = &変数名;

主な特徴

  • 変数のアドレスを格納するために使用されます。
  • null値を代入することができます。
  • 参照渡し(pass by reference)によって参照できます。
  • ポインタ自体もスタック上に独自のメモリアドレスとサイズを持ちます。

サンプルコード

#include <iostream>
using namespace std;

int main() {
    // 通常の整数型変数
    int a = 7;
    // 変数aのアドレスを保持するポインタ変数
    int *p = &a;
    // ポインタが指す値(変数aの値)を表示
    cout << "Value of Variable : " << *p << endl;
    // 変数aのアドレスを表示
    cout << "Address of Variable : " << p << endl;
    // 値を再代入
    *p = 6;
    cout << "Value of the variable is now: " << *p << endl;
    return 0;
}

実行結果

Value of Variable : 7
Address of Variable : 0x6ffe34
Value of the variable is now: 6

C++のスマートポインタ(Smart Pointer)

スマートポインタは抽象データ型の一種で、通常のポインタを、ファイルハンドリングやネットワークソケットといったリソース管理のように扱えるようにする仕組みです。オブジェクトの自動破棄や参照カウントなど、多彩な機能を実現できます。

C++では、スマートポインタはテンプレートクラスとして実装され、間接参照演算子「*」とアロー演算子「->」をオーバーロードします。C++のライブラリで利用できるスマートポインタには、auto_ptr、shared_ptr、unique_ptr、weak_ptrがあります。なお、auto_ptrはC++11で非推奨となり、C++17で削除されたため、現在はunique_ptrやshared_ptrの使用が推奨されています。

サンプルコード

#include <iostream>
using namespace std;

// 汎用のスマートポインタクラス
template <class T>
class Smartpointer {
    T *p; // 実際のポインタ
public:
    // コンストラクタ
    Smartpointer(T *ptr = NULL) {
        p = ptr;
    }
    // デストラクタ:オブジェクト破棄時にメモリを自動解放
    ~Smartpointer() {
        delete(p);
    }
    // 間接参照演算子(*)のオーバーロード
    T & operator * () {
        return *p;
    }
    // アロー演算子(->)のオーバーロードにより、
    // ポインタのようにTのメンバへアクセス可能
    T * operator -> () {
        return p;
    }
};

int main() {
    Smartpointer<int> p(new int());
    *p = 26;
    cout << "Value is: " << *p;
    return 0;
}

実行結果

Value is: 26

C++の共有ポインタ(shared_ptr)

shared_ptrは、C++標準ライブラリが提供するスマートポインタの一種です。生ポインタ(raw pointer)を内包するコンテナであり、参照カウント(オブジェクトやメモリブロック、ディスク領域などのリソースに対する参照・ポインタ・ハンドルの数を記録する手法)を用いた所有権管理の仕組みを、shared_ptrのすべてのコピーと協調して動作させます。

内包する生ポインタが参照するオブジェクトは、そのshared_ptrのすべてのコピーが破棄された時点で初めて解放されます。これにより、メモリリークや二重解放といった問題を防ぐことができます。

サンプルコード

#include <iostream>
#include <memory>
using namespace std;

int main() {
    shared_ptr<int> ptr(new int(7));
    shared_ptr<int> ptr1(new int(6));
    cout << ptr << endl;
    cout << ptr1 << endl;
    // 同じ管理対象オブジェクトを参照している
    // shared_ptrオブジェクトの数を返す
    cout << ptr.use_count() << endl;
    cout << ptr1.use_count() << endl;
    // ptrの所有権を放棄し、内部ポインタはNULLになる
    ptr.reset();
    cout << ptr.get() << endl;
    cout << ptr1.use_count() << endl;
    cout << ptr1.get() << endl;
    return 0;
}

実行結果

0xe80900
0xe80940
1
1
0
1
0xe80940

まとめ

生のポインタは柔軟である一方、メモリ管理をすべて開発者が担う必要があり、バグの原因になりやすいという課題があります。スマートポインタ、特にshared_ptrやunique_ptrを活用することで、RAII(Resource Acquisition Is Initialization)の考え方に基づいた安全なメモリ管理が可能になります。現代のC++では、特別な理由がない限り、生ポインタではなくスマートポインタを使用することがベストプラクティスとされています。

  1. C++のスマートポインタとは?仕組みと使うべき場面をわかりやすく解説

    スマートポインタとは何かスマートポインタとは、C++の「生ポインタ(raw pointer/ベアポインタとも呼ばれます)」をラップするクラスのことです。生ポインタが指し示すメモリなどのリソースを自動的に管理する役割を担います。たとえば、プログラムのどこからもそのメモリ領域への参照が失われてしまった場合でも、スマートポインタは適切なタイミングでメモリを解放してくれます。この動作は、ガベージコレクタに似た働きをすると言えるでしょう。スマートポインタの主な種類C++には複数種類のスマートポインタが用意されており、標準ライブラリでは主に以下の3つが代表的です。std::unique_ptr所有権を1つ

  2. C++のポインタと参照の違いとは?初心者向けにわかりやすく解説

    C++には「参照(リファレンス)」と「ポインタ」という、どちらも間接的に変数を扱うための仕組みがあります。一見似ているこの2つですが、動作や使い方には重要な違いがあります。本記事では、それぞれの基本概念と構文を紹介したうえで、両者の主な相違点をわかりやすく解説します。 参照(Reference)とは 変数を参照として宣言すると、その参照は既に存在する変数の「別名(エイリアス)」として機能します。参照は元の変数と同じメモリ領域を共有するため、参照を通じて行った変更はすべて元の変数に直接反映されます。 構文 型 &新しい名前 = 既存の変数名; 初期化 int x = 10; int &a