题
我知道该函数不允许更改对象的状态,但我想我在某处读到允许编译器假设如果使用相同的参数调用该函数,它将返回相同的值,因此可以重用缓存值(如果可用)。例如
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
类的成员函数 X
, ,类型 this
是 X 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
) 那么指针就变成 const
在一个 const
成员函数,但不是指向的数据,因此可以修改指向的数据。
至于缓存:一般来说,编译器无法执行此操作,因为状态可能会在调用之间发生变化(特别是在我使用互斥体的多线程示例中)。但是,如果定义是内联的,则编译器可以将代码拉入调用函数并优化在那里看到的内容。这可能会导致函数 有效地 只被调用一次。
下一个版本的 C++ 标准 (C++0x) 将有一个新的关键字 constexpr
. 。功能标记 constexpr
返回一个常量值,因此可以缓存结果。在这样的函数中可以执行的操作是有限的(以便编译器可以验证这一事实)。
其他提示
关键词 可变的 on 成员变量允许 const 函数改变当前对象的状态。
不,它不会缓存数据(至少不是所有调用),因为以下代码是随时间变化的有效 const 函数:
int something() const { return m_pSomeObject->NextValue(); }
请注意,尽管指向的对象不是 const,但指针可以是 const,因此对 SomeObject 上的 NextValue 的调用可能会也可能不会改变它自己的内部状态。这会导致该函数每次调用时返回不同的值。
但是,我无法回答编译器如何使用 const 方法。我听说它可以优化某些事情,但我必须查一下才能确定。
不。
const 方法是一种不改变对象状态的方法(即它的字段),但你不能假设给定相同的输入,const 方法的返回值是确定的。换句话说, const
关键字并不意味着该函数是一对一的。例如,返回当前时间的方法是 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++;
}
};