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

13

我知道函数不允许改变对象的状态,但我记得在某个地方读到过,如果函数使用相同的参数调用,则编译器可以假定它将返回相同的值,因此如果可用,它可以重用缓存的值。例如:

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

...


object x;

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

如果是这样,编译器可能会将第二次调用优化掉,并且要么使用寄存器中的值,要么简单地执行b=a;

这是真的吗?

9个回答

27

const 关注的是程序语义而不是实现细节。当成员函数不改变对象的可见状态时,应将其标记为 const,并且可以在一个被标记为 const 的对象上调用这个函数。在类 X 的一个 const 成员函数中,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_ptrboost::shared_ptr),则指针在const成员函数中变为const,但所指向的数据并不是const,因此您可以修改指向的数据。

至于缓存:通常情况下编译器无法进行缓存,因为状态可能会在调用之间发生改变(特别是在具有互斥锁的多线程示例中)。但是,如果定义是内联的,则编译器可以将代码提取到调用函数中,并优化可以在那里看到的内容。这可能导致该函数“实际上”只被调用一次。

下一个C++标准(C++0x)将有一个新关键字constexpr。标记为constexpr的函数返回常量值,因此结果可以被缓存。对于这样的函数,有一些限制(以便编译器可以验证这个事实)。


您让我一天都很开心,先生。我不知道我所需要的就是“mutable”(可变的)。非常感谢你。 - lucastamoios

3

编号。

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


3
关键字mutable用于成员变量,允许const函数改变当前对象的状态。不会缓存数据(至少并非所有调用),因为以下代码是有效的const函数,并且会随着时间而改变:
int something() const { return m_pSomeObject->NextValue(); }

请注意,指针可以是const,尽管指向的对象不是const,因此对SomeObject上的NextValue调用可能会或可能不会改变其自身的内部状态。这导致函数something每次被调用时返回不同的值。
但是,我无法回答编译器如何处理const方法的问题。我听说它可以优化某些东西,但我必须查一下才能确定。

2

在成员函数上使用const关键字会将this参数标记为常量。该函数仍然可以修改全局数据(因此不能被缓存),但无法修改对象数据(允许对常量对象进行调用)。


实际上,如果您有一个标记为mutable的成员,则const函数仍然可以修改它。这主要用于缓存最后的结果。 :-) - 0124816

2

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

对于无副作用的函数(即您想要实现的内容),GCC有一个名为pure的“函数属性”(您可以通过__attribute__((pure))来使用它):http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html


我并不试图实现无副作用的函数。我只是想要理解将一个函数声明为const所带来的所有影响。 - Ferruccio

0

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

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

0

我有疑问,该函数仍然可以调用改变世界状态的全局函数而不违反const。


0

除了成员函数可以修改全局数据之外,它还可以修改显式声明的可变成员对象。


0

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

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


编辑:天啊,被领先了9秒.... 9!!!:)


西部最快枪手,是吗? :-P - C. K. Young
嘿,我的回复比你的早了9秒以上。:P - KTC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接