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

C++でブロック内に作成したオブジェクトはどこに格納される?スタックとヒープの違いを解説

この記事では、C++プログラムにおいて変数やオブジェクトがメモリ上のどこに格納されるのかについて詳しく解説します。C++では、オブジェクトを格納できるメモリ領域は大きく分けて次の2つがあります。

  • スタック − ブロック内で宣言されたローカル変数やオブジェクトは、すべてスタック領域に格納されます。main関数も関数の一種であるため、その内部で宣言された要素も同様にスタックに格納されます。

  • ヒープ − new演算子などで動的に確保されたオブジェクトは、ヒープ領域に格納されます。

スタックに格納されるオブジェクト

ブロックや関数内で宣言されたオブジェクトのスコープは、そのオブジェクトが生成されたブロック内に限定されます。ブロック内で作成されたオブジェクトはスタックに格納され、処理がブロックや関数を抜けると、デストラクタが自動的に呼び出されてオブジェクトは破棄されます。プログラマーが明示的に解放処理を書く必要はありません。

ヒープに格納されるオブジェクト

一方、実行時に動的に確保されたオブジェクトは、ヒープ領域に格納されます。動的な確保はnew演算子によって行います。ヒープ上のオブジェクトはスコープを抜けても自動的に破棄されないため、不要になった時点でdelete演算子を使って明示的に解放する必要があります。解放を忘れるとメモリリークの原因となるので注意しましょう。

サンプルコード

以下の実装例を見て、より理解を深めましょう。

#include <iostream>
using namespace std;
class Box {
    int width;
    int length;
public:
    Box(int length = 0, int width = 0) {
        this->length = length;
        this->width = width;
    }
    ~Box() {
        cout << "Box is destroying" << endl;
    }
    int get_len() {
        return length;
    }
    int get_width() {
        return width;
    }
};
int main() {
    {
        Box b(2, 3); // b はスタックに格納される
        cout << "Box dimension is:" << endl;
        cout << "Length : " << b.get_len() << endl;
        cout << "Width :" << b.get_width() << endl;
    } // ブロックを抜けるとデストラクタが自動的に呼ばれる
    cout << "\tExiting block, destructor" << endl;
    cout << "\tAutomatically call for the object stored in stack." << endl;
    Box* box_ptr;
    {
        // オブジェクト本体はヒープに格納され、
        // ローカルのポインタ変数はスタックに格納される
        Box* box_ptr1 = new Box(5, 6);
        box_ptr = box_ptr1;
        cout << "---------------------------------------------------" << endl;
        cout << "Box 2 dimension is:" << endl;
        cout << "length : " << box_ptr1->get_len() << endl;
        cout << "width :" << box_ptr1->get_width() << endl;
        delete box_ptr1; // delete で明示的に破棄
    }
    cout << "length of box2 : " << box_ptr->get_len() << endl;
    cout << "width of box2 :" << box_ptr->get_width() << endl;
}

実行結果

Box dimension is:
Length : 2
Width :3
Box is destroying
        Exiting block, destructor
        Automatically call for the object stored in stack.
---------------------------------------------------
Box 2 dimension is:
length : 5
width :6
Box is destroying
length of box2 : 0
width of box2 :0

コードのポイント

  • 1つ目のBoxオブジェクト b:ブロック内で通常の宣言により生成されているため、スタックに格納されます。ブロックを抜けた時点でデストラクタが自動的に呼び出され、実行結果に「Box is destroying」と表示されていることが確認できます。

  • 2つ目のBoxオブジェクト:new演算子で動的に確保されているため、オブジェクト本体はヒープに、ポインタ変数 box_ptr1 自体はスタックに格納されます。deleteを実行した時点で「Box is destroying」が出力され、明示的に破棄されています。

注意点

なお、サンプルコードの最後では、すでにdeleteで破棄済みのオブジェクトに対して、ポインタ box_ptr 経由でアクセスしています。これはダングリングポインタへのアクセスであり、未定義動作を引き起こす危険な書き方です。実際の開発では、delete後のポインタにnullptrを代入する、あるいは破棄済みオブジェクトへアクセスしないようにするなどの対策が推奨されます。

  1. C++の標準出力ストリーム(std::cout)とは?基本と使い方を解説

    std::coutとは std::coutは、char型などのナロー文字(半角文字)向けの標準出力ストリームを表す、ostreamクラスのオブジェクトです。C言語の標準出力であるstdoutに対応しており、C++における最も基本的な出力手段となります。 標準出力ストリームとは、実行環境によって決定されるデフォルトの文字出力先のことです。この出力先は、エラー出力用のcerrやログ出力用のclogなど、他の標準オブジェクトと共有される場合もあります。 std::coutの特徴 ostreamクラスのオブジェクトであるstd::coutには、主に次の2つの方法で文字を出力できます。 整形済みデー

  2. C/C++からPythonオブジェクトを操作する方法(Cython埋め込みの実践ガイド)

    C/C++からPythonオブジェクトを使うには?CやC++のプログラムからPythonオブジェクトを直接生成・操作したい場合、Cythonを利用するのが最も手軽な方法の一つです。ここでは、シンプルなPythonクラスをCythonでラップし、C言語側に組み込んで(埋め込んで)呼び出す例を紹介します。C++の場合も手順はほぼ同じで、コンパイル時に--cplusオプションを付けるだけで対応できます。ステップ1:Pythonクラスと公開関数を定義する(pycls.pyx)まず、ラップ対象となるPythonクラスと、C側から呼び出せるようにするためのcdef public関数を定義したファイル「py