mutable关键字解析
c++11
引入mutable
关键字,它是一个类型修饰符,用来修饰成员变量或者是lambda
函数,接下来分布来说明。
修饰成员变量
当mutable
用来修饰成员变量时,表明该成员变量属于对象内部可变
状态,对外不可见。即使在const
函数也可改变,不影响外部使用者对此const
函数的逻辑语义。比如,基于mutex
的线程安全队列。
class Queue{
public:
void push(int x);
void pop(int& x);
bool empty()const{
std::lock_guard<std::mutex> lk(mutex_);
}
private:
// 一定要加`mutable`修饰,否则会编译出错。
mutable std::mutex mutex_;
};
在上述例子中,empty
函数用来判断当前队列是否为空,从语义上看,该函数不会改变队列内部元素个数,加上const
修饰,向编译器明确明该语义。由于内部访问了队列,因此需要加锁,加锁这个动作会改变锁状态,这和const
的语义有冲突,不增加mutable
修饰该锁变量,会编译失败,因此标准引入mutable
修饰符,声明该变量是始终可修改的。
修饰lambda函数
当它用来修饰lambda
函数时,可在lambda
函数体内修改外部的拷贝入参,实例如下:
int x{ 0 };
auto f1 = [x]() mutable{x = 42; printf("2. %d\n", x); };
auto f2 = [x]() {x = 42; printf("2. %d\n", x); }; // 编译出错
auto f3 = [&x]() {x = 42; printf("2. %d\n", x); }; // 编译通过
编译f2
会触发编译错误,提示无法在非可变lambda中修改通过复制捕获
。对此函数加上mutable
,使得该匿名函数支持修改拷贝入参。
注意,通过拷贝传参时,lambda
函数内部对该参数的修改不会影响外部值。如果是传引用,可不加mutable
。