关于c ++:由非const成员函数更改的可变变量

Mutable variable changed by a non-const member function

我正在研究C ++,并且我读到:如果数据成员被声明为可变,那么从const成员函数为该数据成员赋值是合法的。
但是下面的代码编译没有任何错误或gcc的警告。
(这不是一个真实的代码示例,我只是编写它来测试mutable关键字)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class M
{
public:
  M(){x=10;};
  int getX() {x++; return x;};
private:
  mutable int x;
};

int main()
{
  M xx;
  std::cout << xx.getX() << std::endl;
}

我不应该将getX声明为const吗?

编辑1(ForEver的答案使事情更清楚),以下代码将不会被编译:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class M
{
public:
  M(){x=10;};
  int getX() const {x++; return x;};
private:
  int x;
};

int main()
{
  M xx;
  std::cout << xx.getX() << std::endl;
}


const函数中修改mutable是合法的,当然修改non-const函数中的mutable是合法的(因为每个non-const member-variable)。 mutable关键字允许在const函数中修改变量,但不对non-const函数中的修改提供任何限制。


声明意味着这一点。

1
2
3
4
5
6
7
8
9
10
11
12
13
class M
{
public:
   M(){x=10;};
   int getX() const
 //           ^^^^^ If a member function is const...

                   {x++; return x;};
 //                 ^^^ ...and it modifies a member variable...
private:
   mutable int x;
// ^^^^^^^ ...then that variable must be mutable.
};


mutable通常用于允许const限定的成员函数修改缓存的数据。你可以将getX()声明为const并愉快地修改x,这就是mutable的用途。然而,通常认为修改成员函数中对象的内部状态是一个坏主意,因为它声明它没有。

例如,您有一个const成员函数,它根据容器的内容计算值。如果容器有很多元素,可能需要很长时间才能得到结果。如果结果仅在您从容器中添加或删除元素时发生更改,则可以将其缓存以供以后使用。由于成员函数是const限定的,因此您需要将结果变量声明为mutable。由于结果可以从容器中的现有数据计算,因此缓存的值不被视为对象内部状态的一部分,并且从const函数开始,它被认为可以修改它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int Foo::CalcResult() const
{
    if(hasValidCache_ == false)
    {

        // ... recalc value ...

        // Cache the result
        hasValidCache = true;
        cachedValue_ result;
    }

    return cachedValue_;
}