mutable从字面意思来说,是「可变的;会变的」

修饰类的成员变量,用来突破const的限制

#include <iostream>
class Person{
public:
    explicit Person(int a):age(a){ }
    ~Person(){ }

    int getAge() const
    {
        counter++;
        return age;
    }

private:
    int age{18};
    mutable int counter{0};
};

int main() {
    const Person person(20);
    std::cout << "age = " << person.getAge() << std::endl;
    return 0;
}

在上述代码中,如果counter不用mutable修饰,是无法通过编译的。 因为getAge函数是被const修饰的,,在其内部无法修改该类的成员变量。

const意思是“这个函数不修改对象内部状态”,为了保证这一点,编译器会主动替你检查,确保你没有修改对象成员变量——否则内部状态就变了。而mutable意思是“这个成员变量不算对象内部状态”。把这个counter计数变量声明为mutable,编译器就明白了:这个变量不算对象内部状态,修改它并不影响const语义,所以就不需要禁止const函数修改它了

在Lambda表达式中捕获修改表达式之外的变量值

lambda表达式的用法:

[捕获列表] (函数参数) mutable或exception声明 -> 返回值类型 {函数体}

其中mutableexception声明以及返回值类型可以忽略不写。 捕获列表的值又可以有以下几种形式:

  • [] 表示不捕获任何变量
  • [=] 表示按值传递的方法捕获父作用域的所有变量
  • [&] 表示按引用传递的方法捕获父作用域的所有变量
  • [=, &a] 表示按值传递的方法捕获父作用域的所有变量,但按引用传递的方法捕获变量a
  • [&, a] 表示按引用传递的方法捕获父作用域的所有变量,但按值传递的方法捕获变量a

其中按值捕获[=]的方式不允许程序员在Lambda函数的函数体中修改捕获的变量。而以mutable修饰Lambda函数则可以打破这种限制

#include <iostream>
int main() {
    int x{0} ;
    auto f1 = [=]() mutable {return ++x;};
    f1();
    std::cout << "x = " << x << std::endl;
    return 0;
}

上面代码不加mutable是无法通过编译的; 即使加上mutable,也只能在lambda表达式内部改变x的值,在main函数中,x的仍旧是0