web-dev-qa-db-ja.com

「this」ポインタのタイプ

タイトルで述べたように、'this'ポインターのタイプについて知りたいのですが。

私はプロジェクトに取り組んでおり、VC++ 2008を使用するWindowsでは'this'ポインタのタイプが"ClassName * const this"であることに気付きました。まあ、このポインタを定数ポインター。ありがとう。

31
Purnima

このポインターのタイプは、クラスClassNameの非constメソッドまたはconstメソッドの内部で検査されるかどうかに応じて、ClassName *またはconst ClassName *のいずれかになります。ポインターthisは左辺値ではありません。

class ClassName {
  void foo() {
    // here `this` has `ClassName *` type
  }

  void bar() const {
    // here `this` has `const ClassName *` type
  }
};

上記の観察は誤解を招くものです。ポインタthislvalueではない(つまり、ClassName * const型を持つことができない、つまり、 const*の右側にあります。ポインター型の左辺値以外は、constまたはnon-constにすることはできません。 C++言語には、そのような概念はありません。あなたが観察したものは、特定のコンパイラの内部の奇妙なものでなければなりません。正式には正しくありません。

言語仕様からの関連する引用は次のとおりです(強調は私のものです)

9.3.2 this thisポインタ

非静的(9.3)メンバー関数の本体では、キーワードthisはprvalue式であり、その値は、関数が呼び出されるオブジェクトのアドレスです。 クラスXのメンバー関数におけるthisの型はX *です。メンバー関数がconstと宣言されている場合、これの型はconst X *です。メンバー関数がvolatileと宣言されている場合、これの型はvolatile X *、およびメンバー関数がconst volatileと宣言されている場合、これのタイプはconst volatile X *です。 [注:したがって、constメンバー関数では、関数が呼び出されるオブジェクトはconstを介してアクセスされますアクセスパス。 —エンドノート]


C++ 98/C++ 03時代に戻って、いくつかのコンパイラが内部実装トリックを使用したことは何の価値もありません。それらはthisポインタを定数ポインタとして解釈しました。クラスClassNameの非定数メソッドのClassName *const。これは明らかに彼らがthisの変更不可性を保証するのに役立ちました。 GCCとMSVCはこの手法を使用したことが知られています。言語レベルではthisは左辺値ではなく、その一貫性は検出できなかったため、これは無害なトリックでした。その余分なconstは、通常、コンパイラーによって発行された診断メッセージでのみ明らかになります。

ただし、C++ 11での右辺値参照の出現により、constの型でこの余分なthisを検出できるようになりました。たとえば、次のコードはC++ 11で有効です。

struct S
{
  void foo() { S *&&r = this; }
};

それでも、通常は前述のトリックを使用する実装ではコンパイルできません。その後、GCCはこの手法を放棄しました。 MSVC++は引き続きそれを使用します(VS2017以降)。これにより、上記の完全に有効なコードがMSVC++でコンパイルできなくなります。

47
AnT

Constは、ポインタが指すものを変更できないことを意味します。

ClassName *const

とは大きく異なります

const ClassName *

後者はオブジェクトへのポインターであり、オブジェクトは(とにかくポインターを使用して)変更できません。前者は、少なくとも厄介なキャストに頼らない限り、別のオブジェクト(またはNULL)に再ポイントできないポインターです。

もちろん組み合わせもあります:

const ClassName *const

これは、別のものを指すように変更できないポインターであり、また、それが指すオブジェクトを変更するために使用することもできません。

コンパイラーがthisポインターをconstとして表示する理由については、thisを最初のオブジェクト以外のオブジェクトにポイントすることはお勧めできません。

3
John Zwinck

上記で多くの議論があり、メインポストは正解を提示しませんでした。人々はコメントを掘らないかもしれないので、メインポート(PS)として共有する方が良いです。

UbuntuとVC++で調査を行いましたが、正しい出力がありません(typeid(X).nameを使用)。


クラス型Xのメンバー関数に対するこのポインターの型は、X * constです。メンバー関数がconst修飾子で宣言されている場合、クラスXのそのメンバー関数のthisポインターの型はconst X * constです。 MSDNリンク


概念的にはこれも正しいです。通常のメンバー関数は "X * const"であるため、l値ではありません(その内容を変更できないため)。

1
nky