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

C++のポインタで別の関数からローカル変数にアクセスすることは可能?仕組みと危険性を解説

C++において、ローカル変数はスコープを抜けた時点でアクセスできなくなります。それが「ローカル変数」というものの本質だからです。ただし、スコープ外でもローカル変数のメモリにアクセスできる「可能性がある」例を見てみましょう。

サンプルコード

#include<iostream>
int* foo() {
    int x = 3;
    return &x;
}
int main() {
    int* address = foo();
    cout << *address;
    *address = 12;
    cout << *address;
}

出力結果

環境によっては次のような出力になることがあります。

3
12

なぜ動作してしまうのか

先ほど述べたとおり、このコードはあくまで「動作するかもしれない」というレベルです。ここで行っているのは、かつて x のアドレスだったメモリ領域に対する読み書きにすぎません。

main 関数内ではすでに foo のスコープ外にいるため、address はどこかのランダムなメモリ領域を指すポインタとなっています。上記の例では、そのメモリ領域がまだ存在しており、他の処理が使用していないため、読み書きを続けても何も壊れません(別プロセスのメモリや不正なメモリ領域には触れないため)。また、まだ何も上書きされていないため、値の 3 がそのまま残っているのです。

実際のプログラムでは危険

しかし現実のプログラムでは、そのメモリはほぼ即座に再利用される可能性があり、このような操作によって予期せぬデータ破壊を引き起こしかねません。この種のメモリアクセスバグは、原因の特定と修正が非常に難しいことで知られています。

foo 関数から戻る際、プログラムはOSに対して「x のメモリはもう使用されていないので、他の用途に割り当ててよい」と通知します。運が良ければメモリが再割り当てされず、OSにも検知されないまま見逃されるかもしれませんが、それは偶然にすぎません。

まとめ:これは未定義動作

スコープを抜けたローカル変数へのポインタは「ダングリングポインタ(宙ぶらりんポインタ)」と呼ばれ、これを参照解決する行為はC++の規格上未定義動作(Undefined Behavior)に該当します。コンパイラの最適化や実行環境によって、正しく見える出力・クラッシュ・まったく異なる挙動など、どんな結果になり得ます。実務では絶対に避けるべきパターンであり、必要であれば動的確保(new/delete やスマートポインタ)、静的変数、または戻り値による値渡しなどの安全な手法を採用しましょう。

  1. C++とOpenCVを使って画像を各チャネルに分割する方法

    RGB画像には「赤・緑・青」の3つのチャネルが含まれています。赤、緑、青の各チャネルで画像を表現する色空間はRGBカラースペースと呼ばれます。ただし、OpenCVではRGBの代わりにBGRの順序が採用されている点に注意が必要です。つまり、第1チャネルが青(Blue)、第2チャネルが緑(Green)、第3チャネルが赤(Red)となります。画像を各チャネルに分割するには、まず3チャネル分の行列を定義します。ここでは「Mat different_Channels[3]」という形式で3チャネルの行列を宣言します。次に、OpenCVのsplit()関数を使って読み込んだ画像を分割します。この関数の書式は

  2. C++とOpenCVで画像を読み込んで表示する方法を徹底解説

    この記事では、C++でOpenCVを使用して画像を読み込み、表示する方法について詳しく解説します。OpenCVで画像の読み込みや表示を行うには、以下のような関数やデータ構造が必要になります。 画像処理に必要な基本要素 Mat(マトリクス) Matは関数ではなく、データ構造の一種である変数型です。C++におけるint型やchar型、string型のように、MatはOpenCV独自の変数型であり、画像を格納するための行列(マトリクス)データ構造を作成します。プログラム内で「Mat myImage;」と記述した場合、「myImage」という名前の行列変数を宣言していることになります。 name