3

次のコードがあるとします。

class foo;

foo* instance = NULL;

class foo
{
public:
   explicit foo(int j)
    : i(j)
   {
      instance = this;
   }

   void inc()
   {
      ++i;
   }

private:
   int i;
};

以下は定義された動作を使用していますか?

const foo f(0);

int main()
{
   instance->inc();
}

クラスレジストリを使用しているので質問しています。直接変更しないfので、それを作成するといいのですconstが、後でfレジストリによって間接的に変更されます。

編集:定義された動作とは、つまり、オブジェクトは一度しか書き込めない特別なメモリ位置に配置されているということですか? 少なくとも C++1x の constexpr までは、読み取り専用メモリは問題外です。たとえば、定数プリミティブ型は (多くの場合) 読み取り専用メモリに配置され、const_castそれに対して a を実行すると、次のような未定義の動作が発生する可能性があります。

int main()
{
    const int i = 42;
    const_cast<int&>(i) = 0; // UB
}
4

7 に答える 7

4

はい、7.1.5.1/4 によると、未定義の動作です。

ミュータブル (7.1.1) と宣言されたクラス メンバーを変更できることを除いて、その有効期間中 (3.8) に const オブジェクトを変更しようとすると、未定義の動作が発生します。

コンストラクターの呼び出しが完了すると、オブジェクトの有効期間が始まることに注意してください (3.8/1)。

于 2009-12-19T23:27:04.733 に答える
1

const オブジェクトで非 const (宣言による) メンバー関数を呼び出すこと自体は違法ではありません。コンパイラの制限を回避するには、任意の方法を使用できconst_castます。例のように、明示的またはコンストラクターを使用したトリックのいずれかです。

ただし、呼び出しているメンバー関数が実際にオブジェクトを物理的に変更しようとしない限り(つまり、定数オブジェクトの可変でないメンバーを変更する場合)、動作は定義されます。変更を実行しようとすると、動作が未定義になります。あなたの場合、メソッドincはオブジェクトを変更します。つまり、あなたの例では動作は未定義です。

メソッドを呼び出すだけでも、完全に合法です。

于 2009-12-19T23:24:35.923 に答える
0

これらの任意の名前で意図を伝えるのは困難です。iが単なる使用カウンターとして意図されていて、実際にはデータの一部と見なされていない場合は、次のように宣言するのが完全に適切mutable int i;です。一方、モデル化されている空間に意味のあるデータがある場合、それは非常に悪いことです。constii

ただし、それとは別に、あなたの例は、あなたが求めているように見えるものを少し混乱させています。foo* instance = NULL;は効果的に (紛らわしいかもしれませんが) NULLa を数値ゼロとして使用し、 を初期化しますinstanceが、これは ではありませんconst。次に、個別に初期化しますf。これは ですがconst、参照することはありません。

于 2009-12-19T23:18:54.983 に答える
0

少なくとも GCC では、コンストラクターにexplicit foo(int j)int.

ただし、同じ値への 2 つのポインター (1 つはそうでない)constがあってもまったく問題ありません。

于 2009-12-19T23:21:18.490 に答える