66

「this」ポインタはメモリのどこに保存されていますか? スタック、ヒープ、またはデータ セグメントに割り当てられていますか?

#include <iostream>
using namespace std;

class ClassA
{
    int a, b;

    public:
        void add()
        {
            a = 10;
            b = 20;
            cout << a << b << endl;
        }
};

int main()
{
    ClassA obj;
    obj.add();
    return 0;
}

上記のコードでは、メンバー関数を呼び出してadd()おり、レシーバー オブジェクトは「this」ポインターとして暗黙的に渡されます。メモリのどこにthis保存されますか?

4

6 に答える 6

79

this最も簡単な方法は、常に自動的に渡される隠された追加の引数であると考えることです。

したがって、次のような架空の方法:

size_t String::length(void) const
{
  return strlen(m_string);
}

実際には、ボンネットの下で次のようになります。

size_t String__length(const String *this)
{
  return strlen(this->m_string);
}

そして次のような呼び出し:

{
  String example("hello");
  cout << example.length();
}

次のようになります。

cout << String__length(&example);

上記の変換は単純化されていることに注意してください。うまくいけば、私の主張が少し明確になります。コメントを「メソッドオーバーロードのマーシャリングはどこですか?」タイプの異議で埋める必要はありません。:)

これにより、質問は「引数はどこに保存されていますか?」に変わりますが、答えはもちろん「場合による」です。:)

多くの場合、スタック上にありますが、レジスター内、またはコンパイラーがターゲットアーキテクチャーに適していると見なすその他のメカニズム内にある可能性もあります。

于 2013-05-16T10:56:56.827 に答える
65

他の回答は、典型的なコンパイラがどのように実装するかを説明する非常に良い仕事をしthisました(暗黙の最初のパラメータとして関数に渡すことによって)。

C++ ISO 仕様がこれについて明示的に述べていることを確認することも役立つと思います。C++03 ISO 仕様、§9.3.2/1 によると:

非静的 (9.3) メンバー関数の本体では、キーワードthisは、関数が呼び出されるオブジェクトのアドレスを値とする非左辺値式です。

は変数でthisないことに注意することが重要です。これは式であり、式がであるのとほぼ同じ1 + 2 * 3です。この式の値は、ほとんどどこにでも格納できます。コンパイラはそれをスタックに置いて暗黙的パラメータとして関数に渡したり、レジスタに置いたり、ヒープやデータセグメントに置いたりする可能性があります。C++ 仕様では、意図的に実装にある程度の柔軟性を与えています。

「言語弁護士」の答えは、「これは完全に実装定義であり、さらにthis技術的にはポインターではなく、ポインターに評価される式です」だと思います。

お役に立てれば!

于 2013-05-16T15:54:43.997 に答える
18

thisは右辺値 (そのアドレスを取得することはできません) であるため、(必然的に) メモリをまったく占有しません。コンパイラとターゲット アーキテクチャに応じて、多くの場合レジスタに格納されます。Sparc では i0、Intel では MSVC を使用する ECX などです。オプティマイザがアクティブな場合は、移動することさえできます。(MSVCのさまざまなレジスタで見ました)。

于 2013-05-16T11:28:00.743 に答える
11

thisほとんどの場合、関数の引数のように動作し、スタックに格納されるか、アーキテクチャのバイナリ呼び出し規約で許可されている場合はレジスタに格納されます。

于 2013-05-16T10:57:12.580 に答える
1

this適切に定義された場所に保存されていません! それが指しているオブジェクトはどこかに格納されており、明確に定義されたアドレスを持っていますが、アドレス自体には特定のホームアドレスがありません。それはプログラムの中で伝えられます。それだけでなく、そのポインターのコピーが多数存在する可能性があります。

次の架空のinit関数では、オブジェクトはそれ自体を登録して、イベントとタイマー コールバックを受信します (架空のイベント ソース オブジェクトを使用)。したがって、登録後、次の 2 つの追加コピーがありthisます。

void foo_listener::init()
{
   g_usb_events.register(this); // register to receive USB events
   g_timer.register(this, 5);   // register for a 5 second timer
}

I 関数アクティベーション チェーンでは、this ポインターの複数のコピーも存在します。オブジェクトがあり、その関数objを呼び出すとします。fooその関数は同じオブジェクトのbar関数をbar呼び出し、 という別の関数を呼び出しupdateます。各機能起動レベルにはthisポインターがあります。これは、マシン レジスタ、または関数アクティベーションのスタック フレーム内のメモリ位置に格納されます。

于 2013-05-16T15:08:28.583 に答える