一文详解C++中的mutable关键字
mutable修饰类的成员变量
以下实例代码有一个类Person,内部有一个age成员变量表示年龄,有一个被const修饰的公共方法获取年龄:
#include <iostream> class Person{ public: explicit Person(int a):age(a){ } ~Person(){ } int getAge() const{ return age; } private: int age{18}; }; int main() { const Person person(20); std::cout << "age = " << person.getAge() << std::endl; return 0; }
假如我想扩展一下这个类Person的功能,在其内部增加一个counter的字段,用于统计getAge方法的调用次数,于是将其代码改成一下这样子:
#include <iostream> class Person{ public: explicit Person(int a):age(a){ } ~Person(){ } int getAge() const{ counter++; return age; } private: int age{18}; int counter{0}; }; int main() { const Person person(20); std::cout << "age = " << person.getAge() << std::endl; return 0; }
我们发现代码无法编译通过了,因为getAge函数是被const修饰的,被const修饰的函数,在其内部无法修改该类的成员变量。为了可以让代码通过编译并能顺利运行, 于是我们把第10行和第20行的const去掉即可。
这个解决方案可以说是正确的,但是同时也在一定程度傻姑娘破坏了我们设计者的本意,因为程序设计者的本意仅仅是希望counter可以被修改,而age还是不能随意修改的, 把const删除后age也可以随意修改了,同时在《Effective C++》一书中作者也提到过一条准则就是只要可能就用 const
,明显这个Person也是适合使用const修饰的, 那么我们怎样修改才能做到既使用const保证其他变量不可随意修改,又能保证在const函数体内counter可以修改呢?这时候mutable的关键字的作用就体现出来了。
我们仅仅需要在声明counter变量时使用mutable修饰一下即可,也就是:
class Person{ public: explicit Person(int a):age(a){ } ~Person(){ } int getAge() const{ counter++; return age; } private: int age{18}; mutable int counter{0}; };
同理,如果我们希望在被const修饰的函数getAge内age变量也可被修改的话,也可以使用mutable修饰age变量。
mutable在Lambda表达式中的作用
C++11标准中引入了 Lambda 表达式,用于定义匿名函数,使得代码更加灵活简洁。
我们简单回顾一下Lambda表达式的语法,Lambda表达式的语法主要分为五个部分,对应为:
[捕获列表] (函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}
其中 mutable 或 exception 声明
以及返回值类型
是可以忽略不写的。
捕获列表的值又可以有以下几种形式:
包括下面几种形式:
- [] 表示不捕获任何变量
- [=] 表示按值传递的方法捕获父作用域的所有变量
- [&] 表示按引用传递的方法捕获父作用域的所有变量
- [=, &a] 表示按值传递的方法捕获父作用域的所有变量,但按引用传递的方法捕获变量a
- [&, a] 表示按引用传递的方法捕获父作用域的所有变量,但按值传递的方法捕获变量a
其中按值捕获[=]
的方式不允许程序员在 Lambda 函数的函数体中修改捕获的变量。而以 mutable 修饰 Lambda 函数,则可以打破这种限制。
例如一下代码是无法编译通过的:
#include <iostream> int main() { int x{0} ; auto f1 = [=]() {return ++x;}; f1(); std::cout << "x = " << x << std::endl; return 0; }
因为Lambda表达式f1,在内部修改了表达式外部x的值,但是又没有使用mutable关键字声明,此时我们只需要使用mutable关键字声明一下f1即可:
#include <iostream> int main() { int x{0} ; auto f1 = [=]() mutable {return ++x;}; f1(); std::cout << "x = " << x << std::endl; return 0; }
在这里考考大家一个简单的问题,为什么在f1内部改变了外部x的值,但是打印x的值还是0呢?为何没有生效呢?
针对以上例子如果想要在表达式外部修改x的值,笔者觉得直接在捕获列表中使用引用传递不是更加方便明了吗,mutable关键字在Lambda表达式中是否有点脱裤子放屁的感觉?
以上就是一文详解C++中的mutable关键字的详细内容,更多关于C++ mutable关键字的资料请关注脚本之家其它相关文章!
相关文章
简要对比C语言中的setgid()函数和setregid()函数
这篇文章主要介绍了C语言中的setgid()函数和setregid()函数的简要对比,是C语言入门学习中的基础知识,需要的朋友可以参考下2015-08-08详解C++中const_cast与reinterpret_cast运算符的用法
这篇文章主要介绍了C++中const_cast与reinterpret_cast运算符的用法,经常被用于表达式中的类型转换,需要的朋友可以参考下2016-01-01
最新评论