14

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

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;

これは本当ですか?

4

9 に答える 9

26

constプログラムのセマンティクスに関するものであり、実装の詳細に関するものではありません。constオブジェクトの可視状態を変更しない場合はメンバー関数をマークする必要があり、それ自体であるオブジェクトで呼び出し可能にする必要がありますconstconstclassのメンバ関数内ではX、 の型thisX const *: 定数Xオブジェクトへのポインタです。したがって、すべてのメンバー変数は実質的constにそのメンバー関数内にあります (1 つを除く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)、ポインターはconstメンバーconst関数になりますが、ポイント先のデータにはならないため、ポイント先のデータを変更できます。

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

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

于 2008-09-19T08:56:48.350 に答える
3

いいえ。

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

于 2008-09-19T01:52:14.157 に答える
3

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

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

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

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

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

于 2008-09-19T01:55:31.920 に答える
2

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

于 2008-09-19T01:47:15.400 に答える
2

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

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

于 2008-09-19T01:48:19.190 に答える
0

私はそれを疑っています、関数はまだ世界の状態を変えて、constに違反しないグローバル関数を呼び出すことができました。

于 2008-09-19T01:43:47.297 に答える
0

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

于 2008-09-19T01:54:08.537 に答える
0

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

class Foo
{
public:
    int bar() const
    {
        static int x = 0;
        return x++;
    }
};
于 2008-09-20T00:35:49.673 に答える
0

Corey は正しいですが、変更可能としてマークされているメンバー変数は const メンバー関数で変更できることに注意してください。

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


編集:くそー、9秒で殴られた.... 9!!! :)

于 2008-09-19T01:55:40.793 に答える