質問

関数がオブジェクトの状態を変更することは許可されていないことは理解していますが、コンパイラは関数が同じ引数で呼び出された場合に同じ値を返すため、再利用できると想定することが許可されているとどこかで読んだ気がしました。キャッシュされた値(使用可能な場合)。例えば

class object
{
    int get_value(int n) const
    {
        ...
    }

...


object x;

int a = x.get_value(1);
    ...
int b = x.get_value(1);

その場合、コンパイラは 2 番目の呼び出しを最適化し、レジスタ内の値を使用するか、単に実行することができます。 b = a;

これは本当ですか?

役に立ちましたか?

解決

const これはプログラムのセマンティクスに関するものであり、実装の詳細に関するものではありません。メンバー関数をマークする必要があります const オブジェクトの表示状態を変更せず、それ自体であるオブジェクトに対して呼び出し可能である必要がある場合 const. 。以内 const クラスのメンバー関数 X, 、の種類 thisX const *:定数へのポインタ X 物体。したがって、すべてのメンバー変数は実質的に const そのメンバー関数内 (除く) mutable もの)。持っている場合は、 const オブジェクト、呼び出すことしかできません const その上のメンバー関数。

使用できます mutable メンバー変数が内部でも変更される可能性があることを示します。 const メンバー関数。これは通常、結果のキャッシュに使用される変数、またはミューテックスなどの実際の監視可能な状態に影響を与えない変数を識別するために使用されます (ミューテックスをロックする必要はあります)。 const メンバー関数)、またはカウンターを使用します。

class X
{
    int data;
    mutable boost::mutex m;
public:
    void set_data(int i)
    {
        boost::lock_guard<boost::mutex> lk(m);
        data=i;
    }
    int get_data() const // we want to be able to get the data on a const object
    {
        boost::lock_guard<boost::mutex> lk(m); // this requires m to be non-const
        return data;
    }
};

データを直接ではなくポインターで保持する場合 (次のようなスマート ポインターを含む) std::auto_ptr または boost::shared_ptr) ポインタは次のようになります constconst メンバー関数ではありますが、ポイント先のデータは対象外であるため、ポイント先のデータを変更できます。

キャッシュに関しては次のようになります。一般に、呼び出し間で状態が変化する可能性があるため、コンパイラーはこれを実行できません (特に、ミューテックスを使用したマルチスレッドの例では)。ただし、定義がインラインの場合、コンパイラーはコードを呼び出し関数に取り込み、そこで表示される内容を最適化できます。これにより、機能が発生する可能性があります 効果的に 呼び出されるのは一度だけです。

次のバージョンの C++ 標準 (C++0x) 新しいキーワードが生まれるだろう constexpr. 。タグ付けされた機能 constexpr 定数値を返すので、結果をキャッシュできます。このような関数で実行できることには制限があります (コンパイラがこの事実を検証できるようにするため)。

他のヒント

キーワード 可変 メンバー変数を使用すると、const 関数でオブジェクトの状態を変更できるようになります。

いいえ、次のコードは時間の経過とともに変化する有効な const 関数であるため、データ (少なくともすべての呼び出しではありません) をキャッシュしません。

int something() const { return m_pSomeObject->NextValue(); }

指すオブジェクトは const ではありませんが、ポインタは const である可能性があることに注意してください。したがって、SomeObject で NextValue を呼び出すと、それ自体の内部状態が変更される場合と変更されない場合があります。これにより、関数 something は呼び出されるたびに異なる値を返すようになります。

ただし、コンパイラが const メソッドでどのように動作するかについては答えることができません。特定のものを最適化できると聞いたことがありますが、確認するには調べる必要があります。

いいえ。

const メソッドは、オブジェクトの状態を変更しないメソッドです (つまり、そのフィールド))、同じ入力が与えられた場合に const メソッドの戻り値が決定されると想定することはできません。言い換えると、 const キーワードは、関数が 1 対 1 であることを意味するものではありません。たとえば、現在時刻を返すメソッドは const メソッドですが、その戻り値は呼び出しごとに変わります。

メンバー関数の const キーワードは、 これ パラメータを定数として使用します。この関数は引き続きグローバル データをミュートできます (したがってキャッシュできません) が、オブジェクト データはミュートできません (const オブジェクトの呼び出しは可能です)。

この文脈では、 const メンバー関数はそれを意味します this として扱われます const ポインタも。実際には、状態を変更することは許可されていないことを意味します。 this の中に const メンバー関数。

副作用のない関数 (つまり、達成しようとしている関数) の場合、GCC には次のような「関数属性」があります。 pure (こう言って使います) __attribute__((pure))): http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

私はそれを疑っていますが、この関数は世界の状態を変更するグローバル関数を呼び出すことができ、const に違反することはありません。

メンバー関数がグローバル データを変更できることに加えて、メンバー関数は、問題のオブジェクトの明示的に宣言された変更可能なメンバーを変更することができます。

Corey は正しいですが、次のようにマークされているメンバー変数は次のとおりであることに留意してください。 可変 できる const メンバー関数で変更できます。

また、これらの関数は他の const 関数から、または他の const 参照を介して呼び出すことができることも意味します。


編集:くそ、9秒差で負けた……。9!!!:)

const メソッドを使用して静的ローカルを変更することもできます。たとえば、以下は完全に正当です (そして bar() を繰り返し呼び出すと、キャッシュされた 0 ではなく、増加する値が返されます)。

class Foo
{
public:
    int bar() const
    {
        static int x = 0;
        return x++;
    }
};
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top