const成员函数的语义是什么?
我知道该函数不允许更改对象的状态,但是我想我读过某个地方,允许编译器假定如果函数使用相同的参数调用,它将返回相同的值,因此可以重用缓存的值(如果有)。例如
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++; } };