SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Modern C++入門

生のポインタは使わないで! Modern C++のメモリ管理

第3回 ポインタはスマートポインタで!

メモリ領域へアクセスする

 初期化の話が済んだら、それをどう使うかという話ですね。unique_ptrとかmake_uniqueとか難しいなぁ、と思っている読者はここで安堵するような話になりますよ。

メモリ領域へアクセス[C++11]

 スマートポインタを使ったメモリ領域へのアクセスは簡単です。そういえば、普通のポインタでメモリ領域へアクセするするにはどうしていましたっけ……? そう、間接参照演算子いわゆるアスタ(*)や、アロー演算子(->)を使っていましたね。これらをそのまま使って、メモリ領域へアクセスできます。

リスト access.cpp
auto u_int_ptr = make_unique<int>(99);
auto s_str_ptr = make_shared<string>("shared");

// operator *()で参照できる
cout << *u_int_ptr << endl;	// 99
cout << *s_str_ptr << endl;	// shared

// operator ->()で、size関数を呼び出せる
auto str_size = s_str_ptr->size();
cout << str_size << endl;	// 6

 2つのポインタは、それぞれint型、string型のスマートポインタです。「*」で参照すれば、整数、文字列の内容がそれぞれ出力されます。「->」で参照すれば、この例のようにstring型のsize関数で文字列長を取得し、出力します。なお、初期化の節で紹介したサンプルには、配布するものには「*」による参照とcoutによる出力が含まれていますので、ぜひ実行して試してください。

[NOTE]演算子のオーバーロードはとても強力

 スマートポインタはあくまでもクラスなので、C/C++の生のポインタに対して使うはずの「*」や「->」はそのままでは使えません。しかし、C++には演算子のオーバーロードという他言語でも備えているのは一握りという強力な機能があるのです。この機能により、演算子が適用されたときの動きをカスタマイズできるのです。例えば、「*」に対してはoperator *()という静的関数が呼び出され、そこに記述されている内容が実行されます。スマートポインタという機能で、かつてのポインタと同様の記法を使えるのは、演算子のオーバーロード機能のおかげなのです。

配列へのアクセス[C++11][C++17]

 スマートポインタが配列であるときもアクセスは簡単です。配列の要素へのアクセスは、[]演算子を使っていました。これをそのまま使えます。C/C++では、生のポインタを使って*(p+10)とかいう式で配列要素へのアクセスをしていた者もいたようですが(筆者です)、スマートポインタを生ポインタのように見なす演算は定義されていませんので(ただし、get関数を使うと中のポインタを取得できる)、[]を使ってアクセスするのが基本です。以下のリストの前半部は前節の「配列の利用」を参照してください。

リスト array.cpp
…略…
// operator [](size_t)を使ってアクセスする
for (int i = 0; i < 10; i++) {
    u_int_array_ptr[i] = i;
    s_str_array_ptr[i] = to_string(i);
}
for (int i = 0; i < 10; i++) {
    cout << u_int_array_ptr[i] << " ";
    cout << s_str_array_ptr[i] << endl;
}

 これってよくある危ないコードに見えますね。ループ変数の上限を増やしてみたらどうなるでしょうか? これは各自でコードを書き換えて実行してほしいのですが、範囲外の要素からは、なんと0や空文字列が返ってきます。変な値が返ってきたり、プログラムが落ちたりしません。これは、範囲外の要素へのアクセスは、自動的に配列が拡張されるからですね。ですので、参照ではなく代入にしてやると、しっかりと配列が拡張されて値が代入されます。これはこれで、ロジックとしては誤っているのに、なぜか動いてしまうということにもなってしまいますが……。

メモリ領域の所有権を確認[C++11]

 スマートポインタを利用する上で、実際にメモリ領域への所有権があるかというのは重要です。「アンタ、本当に持っているんだろうね?」と疑惑を向けられたときにそれを証明する方法を知っておきましょう。

 これはすごく簡単で、スマートポインタのインスタンスをbool型のコンテキストで評価するだけです。持っていればtrue、持っていなければfalseとなります。bool型のコンテキストって?ということなのですが、もっと簡単なのはキャストなどによるbool型としての評価でしょう。このほか、if文の条件式で評価しても同様です。

リスト isown.cpp
auto u_int_ptr = make_unique<int>(100);
auto s_str_ptr = make_shared<string>("hello");

// bool型としての評価で所有権の有無を確認できる
bool is_own_i = (bool)u_int_ptr;
cout << "is own int:" << is_own_i << endl;

// if文の条件式にも使える
if (s_str_ptr) {
    cout << "s_int_ptr has memory." << endl;
} else {
    cout << "s_int_ptr does not have memory." << endl;
}

次のページ
メモリ領域を解放する[C++11]

この記事は参考になりましたか?

Modern C++入門連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/18446 2023/10/20 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー