14

我知道该函数不允许更改对象的状态,但我想我在某处读到允许编译器假设如果使用相同的参数调用该函数,它将返回相同的值,因此可以重用缓存值(如果可用)。例如

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

...


object x;

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

然后编译器可以优化第二次调用,或者使用寄存器中的值或者干​​脆做b = a;

这是真的?

4

9 回答 9

26

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_ptror boost::shared_ptr),则指针变为const成员const函数,而不是指向的数据,因此您可以修改指向的数据。

至于缓存:通常编译器不能这样做,因为状态可能会在调用之间发生变化(尤其是在我使用互斥锁的多线程示例中)。但是,如果定义是内联的,那么编译器可以将代码拉入调用函数并优化它在那里可以看到的内容。这可能会导致该函数实际上只被调用一次。

下一版本的C++ 标准 (C++0x)将有一个新的关键字constexpr. 标记的函数constexpr返回一个常量值,因此可以缓存结果。在这样的函数中可以做的事情是有限制的(以便编译器可以验证这个事实)。

于 2008-09-19T08:56:48.350 回答
3

不。

const 方法是一种不改变对象(即其字段)状态的方法,但您不能假设给定相同的输入,确定 const 方法的返回值。换句话说,const关键字并不意味着该函数是一对一的。例如,返回当前时间的方法是 const 方法,但它的返回值在调用之间发生变化。

于 2008-09-19T01:52:14.157 回答
3

成员变量上的关键字mutable允许 const 函数改变手头对象的状态。

不,它不会缓存数据(至少不是所有调用),因为以下代码是一个有效的 const 函数,会随时间变化:

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

请注意,指针可以是 const,尽管指向的对象不是 const,因此对 SomeObject 上的 NextValue 的调用可能会也可能不会改变它自己的内部状态。这会导致函数在每次调用时返回不同的值。

但是,我无法回答编译器如何使用 const 方法。我听说它可以优化某些东西,尽管我必须查一下才能确定。

于 2008-09-19T01:55:31.920 回答
2

成员函数上的 const 关键字将this参数标记为常量。该函数仍然可以静音全局数据(因此无法缓存),但不能静音对象数据(允许调用 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

Corey 是正确的,但请记住,任何标记为可变的成员变量都 可以在 const 成员函数中进行修改。

这也意味着可以从其他 const 函数或通过其他 const 引用调用这些函数。


编辑:妈的,被打了9秒……9!!!:)

于 2008-09-19T01:55:40.793 回答
0

const 方法也可以修改静态局部变量。例如,以下是完全合法的(并且对 bar() 的重复调用将返回递增的值 - 而不是缓存的 0):

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