码迷,mamicode.com
首页 > 其他好文 > 详细

mutable 关键字

时间:2021-06-16 18:34:32      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:编译器   error   lambda表达式   不可变   表达   优化   理论   mod   直接   

mutable

理解

mutable字面意思是可变的,其实直接定义的local variable都是可变的,所以mutable对于修饰普通的local variable是没有意义的。事实上,编译器会禁止你这么做:

#include <iostream>

int main() {
    mutable int a{0};
    a = 5;
    std::cout << "a=" << a << std::endl;
}

编译报错:

mutable.cpp:4:17: error: ‘mutable‘ can only be applied to member variables

由此可见,mutable用于修饰类的成员变量:

#include <iostream>

int main() {
    struct mu_st {
        mutable int a;
    };
    const mu_st ms{0};
    ms.a = 5;
    std::cout << "a=" << ms.a << std::endl;
}

这里,在一个类mu_st中定义了一个mutable的变量a,并实例化了一个const的对象ms,理论上,因为const性,不允许改变ms对象,但因为a被声明了mutable,它就可以突破const的限制,从而变成可变的。

这就是mutable的作用,在const类或const成员函数中修改一些状态。到这里,不禁要问,声明为const就是为了防止改变对象,现在有搞出来个mutable,这不自相矛盾吗?

确实,上例中,mutable的应用是没有意义的,但在某些场合,mutable却是不可缺少的。其主要场景包括两类(参考 “Effective Modern C++”),第一是在const成员函数需要多线程并发时,第二是为了优化程序运行,做一些与类内部状态无关的缓存,第三类是在lambda表达式中去除采用赋值方式捕获的变量的const属性。这三类场景的应用实例见第二部分。

典型场景

** mutex -- const函数的并发支持 **

c++中实现线程安全的通常做法是使用std::mutex,但是在const成员函数中,对mutex的加锁和释放锁操作会违背const的不可变语义,所以,只能将mutex定义为mutable,从而可以在const修饰的函数中加锁,实现线程安全。

#include <iostream>
class Cal {
public: 
    Cal(int n) {num = n;}

    void inc_num() {
        std::lock_guard<std::mutex> lg(m);
        ++num;
    }

    int get_num() const {
        std::lock_guard<std::mutex> lg(m);
        return num;
    }
private:
    int num;
    mutable std::mutex m;
};

int main() {
    Cal c{0};
    std::cout << c.get_num() << std::endl;
}

** 内部缓存(非类的内部状态)**

内部缓存一般是与类的内部状态无关的,const函数语义上表示不修改类的状态,但有时为了缓存某些计算结果、某些中间数据,需要在const函数中修改一些成员变量,这些变量并不影响类的状态,所以这种const叫做logic const.

#include <iostream>
class Account {
public: 
    float query() const {
        ++query_cnt;
        return total;
    }
 
    float total; // 总账户
    mutable int query_cnt; // 查询次数
};

int main() {
    Account acc{100.0f};
    acc.query();
    acc.query();
    std::cout << "query times: " << acc.query_cnt << std::endl;
}

*** lambda表达式 **

当lambda表达式用[=]捕获变量时,在表达式内部是不允许修改变量的,但是可用mutable允许修改变量:

#include <iostream>

int main() {
    int a = 0;
    auto cb = [=]() mutable {
        a = 1;
        std::cout << "a=" << a << std::endl;
    };
    cb();
    std::cout << "a=" << a << std::endl;
}
a=1
a=0

mutable 关键字

标签:编译器   error   lambda表达式   不可变   表达   优化   理论   mod   直接   

原文地址:https://www.cnblogs.com/ultramanX/p/14889809.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!