提问人:Ferruccio 提问时间:9/19/2008 更新时间:9/20/2008 访问量:6777
常量成员函数的语义是什么?
What are the semantics of a const member function?
问:
我知道不允许该函数更改对象的状态,但我想我在某处读到编译器被允许假设如果使用相同的参数调用该函数,它将返回相同的值,因此可以重用缓存的值(如果它可用)。例如:
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
this
const
对于无副作用的函数(即您要实现的目标),GCC 有一个称为“函数属性”(您可以通过说来使用它):http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.htmlpure
__attribute__((pure))
评论
不。
const 方法是一种不改变对象状态(即其字段)的方法,但你不能假设给定相同的输入,就确定了 const 方法的返回值。换句话说,关键字并不意味着该函数是一对一的。例如,返回当前时间的方法是 const 方法,但其返回值在调用之间会发生变化。const
除了成员函数可以修改全局数据之外,成员函数还可以修改相关对象的显式声明的可变成员。
成员变量上的关键字可变允许 const 函数更改手头对象的状态。
不,它不会缓存数据(至少不是所有调用),因为以下代码是一个随时间变化的有效常量函数:
int something() const { return m_pSomeObject->NextValue(); }
请注意,指针可以是 const,但指向的对象不是 const,因此对 SomeObject 的 NextValue 调用可能会也可能不会改变它自己的内部状态。这会导致函数 something 在每次调用时返回不同的值。
但是,我无法回答编译器如何使用 const 方法。我听说它可以优化某些东西,尽管我必须查找它才能确定。
Corey是正确的,但请记住,任何标记为可变的成员变量都可以在const成员函数中修改。
这也意味着这些函数可以从其他常量函数调用,也可以通过其他常量引用调用。
编辑:该死的,被打了 9 秒......9!!!:)
评论
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
评论
mutable
还允许 const 方法修改静态局部变量。例如,以下内容是完全合法的(重复调用 bar() 将返回递增值 - 而不是缓存的 0):
class Foo
{
public:
int bar() const
{
static int x = 0;
return x++;
}
};
评论