const成员函数的语义是什么?

时间:2020-03-06 14:24:19  来源:igfitidea点击:

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

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

...

object x;

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

然后编译器可以优化第二次调用,并使用寄存器中的值或者简单地执行" b = a;"。

这是真的?

解决方案

我对此表示怀疑,该函数是否仍可以调用一个全局函数,该函数可以更改世界的状态并且不违反const。

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

在这种情况下," const"成员函数意味着" this"也被视为" const"指针。实际上,这意味着不允许我们在const成员函数内修改this的状态。

对于没有副作用的功能(即我们要实现的功能),GCC具有一个称为"纯"的"功能属性"(我们可以通过说" __attribute __((纯))"来使用它): gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

不。

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

除了成员函数可以修改全局数据这一事实之外,成员函数还可以修改所讨论对象的显式声明的可变成员。

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

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

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

请注意,尽管指向的对象不是const,但指针也可以是const,因此对SomeObject的NextValue的调用可能会或者可能不会更改其自身的内部状态。这会使函数每次被调用时都返回不同的值。

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

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

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

编辑:该死,被9秒殴打。 :)

const与程序语义有关,与实现细节无关。当它不改变对象的可见状态时,应标记成员函数const,并且可以在本身为const的对象上调用。在类" X"上的" const"成员函数中," this"的类型为" X const *":指向常量" X"对象的指针。因此,所有成员变量在该成员函数中都是有效的" const"(可变变量除外)。如果有一个" 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,而在pointed成员函数中则变为-数据,因此我们可以修改指向的数据。

至于缓存:通常,编译器无法执行此操作,因为状态可能在两次调用之间改变(尤其是在我使用互斥锁的多线程示例中)。但是,如果定义是内联的,则编译器可以将代码提取到调用函数中,并优化其在此处看到的内容。这可能导致该功能仅被有效调用一次。

下一版本的C ++标准(C ++ 0x)将具有新的关键字" constexpr"。标记为" constexpr"的函数返回一个常数,因此可以将结果缓存。在此函数中可以执行的操作受到限制(以便编译器可以验证这一事实)。

const方法也允许修改静态局部。例如,以下代码是完全合法的(重复调用bar()将返回递增值,而不是缓存的0):

class Foo
{
public:
    int bar() const
    {
        static int x = 0;
        return x++;
    }
};