前段时间我遇到了一些用<code>mutable关键字标记类的成员变量的代码。 据我所知,它只是允许你修改const方法中的变量:

class Foo
{
private:  mutable bool done_;
public:  void doSomething() const { ...; done_ = true; }
};

这是这个关键字的唯一用途,还是有更多的东西比它的眼睛? 我已经在一个类中使用了这个技术,将boost::mutex标记为可变,允许const函数为了线程安全原因而锁定它,但是,说实话,它感觉有点像黑客。


#1楼

您对boost :: mutex的使用正是此关键字的用途。 另一个用途是用于内部结果缓存以加快访问速度。

基本上,'mutable'适​​用于不影响对象外部可见状态的任何类属性。

在您的问题的示例代码中,如果done_的值影响外部状态,则可变性可能不合适,这取决于...中的内容; 部分。


#2楼

Mutable用于将特定属性标记为可在const方法中修改。 这是它的唯一目的。 在使用之前要仔细考虑,因为如果您更改设计而不是使用mutable ,您的代码可能会更清晰,更易读。

http://www.highprogrammer.com/alan/rants/mutable.html

因此,如果上述疯狂不是可变的,它是什么? 这是一个微妙的案例:mutable是指对象在逻辑上不变的情况,但实际上需要改变。 这些案例很少见,但它们存在。

作者提供的示例包括缓存和临时调试变量。


#3楼

在某些情况下(如设计不佳的迭代器),类需要保留计数或其他偶然值,这不会真正影响类的主要“状态”。 这通常是我看到可变使用的地方。 如果没有变数,你将被迫牺牲整个设计的整体性。

对我来说,大部分时间感觉像是黑客。 在极少数情况下有用。


#4楼

它在您隐藏内部状态(如缓存)的情况下很有用。 例如:

class HashTable
{
...
public:string lookup(string key) const{if(key == lastKey)return lastValue;string value = lookupInternal(key);lastKey = key;lastValue = value;return value;}private:mutable string lastKey, lastValue;
};

然后你可以让const HashTable对象仍然使用它的lookup()方法,它修改了内部缓存。


#5楼

它允许区分按位const和逻辑const。 逻辑const是指对象不会以通过公共接口可见的方式更改,例如锁定示例。 另一个例子是一个在第一次请求时计算值的类,并缓存结果。

因为可以在lambda上使用c ++ 11 mutable来表示按值捕获的内容是可修改的(默认情况下不是这样):

int x = 0;
auto f1 = [=]() mutable {x = 42;};  // OK
auto f2 = [=]()         {x = 42;};  // Error: a by-value capture cannot be modified in a non-mutable lambda

#6楼

mutable主要用于类的实现细节。 该类的用户不需要知道它,因此他认为“应该”为const的方法可以。 你的互斥量可变的例子是一个很好的规范例子。


#7楼

嗯,是的,这就是它的作用。 我将它用于通过不在逻辑上改变类状态的方法修改的成员 - 例如,通过实现缓存来加速查找:

class CIniWrapper
{
public:CIniWrapper(LPCTSTR szIniFile);// non-const: logically modifies the state of the objectvoid SetValue(LPCTSTR szName, LPCTSTR szValue);// const: does not logically change the objectLPCTSTR GetValue(LPCTSTR szName, LPCTSTR szDefaultValue) const;// ...private:// cache, avoids going to disk when a named value is retrieved multiple times// does not logically change the public interface, so declared mutable// so that it can be used by the const GetValue() methodmutable std::map<string, string> m_mapNameToValue;
};

现在,您必须小心使用它 - 并发问题是一个大问题,因为调用者可能会认为如果只使用const方法它们是线程安全的。 当然,修改mutable数据不应该以任何重要方式改变对象的行为,例如,如果预期写入磁盘的更改将立即可见,则我可以违反该示例。应用程序。


#8楼

你对它的使用并不是一种破解,虽然像C ++中的很多东西一样,对于一个懒惰的程序员来说,可变的可能是黑客,他们不想一直回来并且标记一些不应该作为非const的const。


#9楼

当你推断允许一个修改其他常量函数中的数据时,确实存在mutable

目的是你可能有一个对对象的内部状态“什么都不做”的函数,所以你标记了函数const ,但你可能真的需要以不影响它的方式修改一些对象状态正确的功能。

关键字可以作为编译器的提示 - 理论编译器可以将一个常量对象(例如全局)放在标记为只读的内存中。 存在可mutable提示,不应该这样做。

以下是声明和使用可变数据的一些正当理由:

  • 线程安全。 声明一个mutable boost::mutex是完全合理的。
  • 统计。 在给定部分或全部参数的情况下,计算对函数的调用次数。
  • 记忆化。 计算一些昂贵的答案,然后将其存储以备将来参考,而不是再次重新计算。

#10楼

如果在类中只有一个变量用于表示诸如互斥锁或锁之类的信号,则使用Mutable。 此变量不会更改类的行为,但是为了实现类本身的线程安全性是必需的。 因此,如果没有“可变”,您将无法拥有“const”函数,因为需要在外部世界可用的所有函数中更改此变量。 因此,引入了mutable,以便使成员变量甚至可以通过const函数进行写入。

指定的mutable通知编译器和读者它是安全的并且期望可以在const成员函数内修改成员变量。


#11楼

对于对用户来说逻辑无状态的事物(因此在公共类'API中应该有“const”getter)时使用“mutable”,但在底层的IMPLEMENTATION(.cpp中的代码)中不是无状态的。

我最常使用的情况是无状态“普通旧数据”成员的惰性初始化。 也就是说,在这种成员构建(处理器)或随身携带(存储器)昂贵的情况下,它是理想的,并且对象的许多用户永远不会要求它们。 在这种情况下,你需要在后端进行延迟构造以提高性能,因为90%的构建对象根本不需要构建它们,但是你仍然需要提供正确的无状态API供公众使用。


#12楼

当覆盖const虚函数并想要修改该函数中的子类成员变量时,mutable可以很方便。 在大多数情况下,您不希望更改基类的接口,因此您必须使用自己的可变成员变量。


#13楼

关键字'mutable'实际上是一个保留的keyword.often它用于改变常量变量的值。如果你想拥有constsnt的多个值,请使用关键字mutable。

//Prototype
class tag_name{::mutable var_name;::};

#14楼

mutable关键字是刺破的方式const你披在你的对象面纱。 如果你有一个const引用或指向对象的指针,你不能以任何方式修改该对象, 除非它被标记为mutable时间和方式。

使用const引用或指针,您将被限制为:

  • 仅对任何可见数据成员的读访问权限
  • 只能调用标记为const方法的权限。

mutable异常使得您现在可以编写或设置标记为mutable数据成员。 这是唯一外部可见的差异。

在内部,您可以看到的那些const方法也可以写入标记为mutable数据成员。 从本质上讲,全面穿孔。 完全取决于API设计者,以确保mutable不会破坏const概念,并且仅用于有用的特殊情况。 mutable关键字有帮助,因为它清楚地标记了受这些特殊情况影响的数据成员。

在实践中,您可以在整个代码库中使用const (您基本上希望用const “疾病”“感染”您的代码库)。 在这个世界中,指针和引用是const ,只有很少的例外,产生的代码更容易推理和理解。 对于一个有趣的题外话,请查看“参考透明度”。

如果没有mutable关键字,最终将被迫使用const_cast来处理它允许的各种有用的特殊情况(缓存,引用计数,调试数据等)。 不幸的是, const_castmutable更具破坏性,因为它迫使API 客户端破坏他正在使用的对象的const保护。 此外,它会导致广泛的const破坏: const_cast一个const指针或引用允许不受限制的写入和方法调用访问可见成员。 相比之下, mutable要求API设计者对const异常进行细粒度控制,通常这些异常隐藏在对私有数据进行操作的const方法中。

(注:我指的是对数据和方法的可视性几次。我讲的成员标记为公共与私有或保护的是讨论一个完全不同类型的对象的保护这里 。)


#15楼

在为类测试目的创建存根时,mutable关键字非常有用。 您可以存根const函数,但仍然可以增加(可变)计数器或您添加到存根的任何测试功能。 这使得存根类的接口保持不变。


#16楼

Mutable将const的含义从bitwise const更改为类的逻辑const。

这意味着具有可变成员的类更长是按位常量,并且将不再出现在可执行文件的只读部分中。

此外,它通过允许const成员函数在不使用const_cast情况下更改可变成员来修改类型检查。

class Logical {mutable int var;public:Logical(): var(0) {}void set(int x) const { var = x; }
};class Bitwise {int var;public:Bitwise(): var(0) {}void set(int x) const {const_cast<Bitwise*>(this)->var = x;}
};const Logical logical; // Not put in read-only.
const Bitwise bitwise; // Likely put in read-only.int main(void)
{logical.set(5); // Well defined.bitwise.set(5); // Undefined.
}

请参阅其他答案以获取更多详细信息,但我想强调它不仅仅是针对type-saftey而且它会影响编译结果。


#17楼

我们使用mutable的最好例子之一是深拷贝。 在复制构造函数中,我们发送const &obj作为参数。 因此创建的新对象将是常量类型。 如果我们想要改变(通常我们不会改变,在极少数情况下我们可能会改变)这个新创建的const对象中的成员我们需要将它声明为mutable

mutable存储类只能用于类的非静态非const数据成员。 即使它是声明为const的对象的一部分,也可以修改类的可变数据成员。

class Test
{
public:Test(): x(1), y(1) {};mutable int x;int y;
};int main()
{const Test object;object.x = 123;//object.y = 123;/* * The above line if uncommented, will create compilation error.*/   cout<< "X:"<< object.x << ", Y:" << object.y;return 0;
}Output:-
X:123, Y:1

在上面的例子中,我们可以更改成员变量x的值,尽管它是声明为const的对象的一部分。 这是因为变量x被声明为可变的。 但是,如果您尝试修改成员变量y的值,编译器将抛出错误。


#18楼

经典的例子(在其他答案中提到)和我见过的迄今为止使用的mutable关键字的唯一情况是缓存复杂的Get方法的结果,其中缓存被实现为类的数据成员而不是作为方法中的静态变量(出于在多个函数之间共享或简单清洁的原因)。

通常,使用mutable关键字的替代方法通常是方法中的静态变量或const_cast技巧。

另一个详细解释在这里 。

除了允许变量被const函数修改之外,'mutable'关键字是否有任何其他用途?相关推荐

  1. C++如何在const函数修改成员变量的值

    C++如何在const函数修改成员变量的值 在C++,总所周知,c++不允许在const函数直接修改成员变量的值,想要达到此目的,有两种方式: 使用mutable关键字 造一个假的this去操作成员变 ...

  2. const、volatile、mutable关键字

     const关键字 变量宏方面: const 修饰变量:常量非指针类型,非指针常量类型并没有什么区别. const修饰指针:常量指针:是指针不过指向的是常量可以进行p++操作不能进行*p操作:指针 ...

  3. python怎么创建变量balance_在Python中将变量从一个函数修改为另一个函数

    以下是有问题的功能: def ATM(): global mode pinNum = input('Please enter your 4 digit secret code: ') userBala ...

  4. C++基本功:全面掌握const、volatile和mutable关键字

    C++ 程式设计过程中 ,const 的使用可以频度是非常高的 . 它在保证程式安全方面起到了不可估量的作用 . 用一句话来表达最确切不过了:"小兵立大功" .    有了 con ...

  5. C++的静态成员变量和静态成员函数

    C++的静态成员变量和静态成员函数 静态成员变量和静态成员函数算是C++面向对象编程中的一个重点和难点,这里的静态具体指什么呢?与普通的成员变量和成员函数相比,静态成员函数和静态成员变量是属于类的,而 ...

  6. 【C/C++ 关键字 存储类说明符】C/C++ 的mutable 关键字 忽略对该数据成员的常量性检查在const函数中修改变量值

    这里写目录标题 1. 引言 1.1 mutable关键字的简介 2. mutable关键字的设计意图 (The Design Intent of the mutable Keyword) 2.1 为什 ...

  7. C++静态成员变量与静态成员函数

    类的静态成员有两种:静态成员变量和静态成员函数,语法是在普通成员变量和成员函数前加static关键字. 0.定义 class CRect{ public:void show();//普通成员函数sta ...

  8. [转]C++中const、volatile、mutable的用法

    原文:https://blog.csdn.net/imJaron/article/details/79657642 const意思是"这个函数不修改对象内部状态". 为了保证这一点 ...

  9. Java 主函数 main 中的关键字 static

    相信很多人在运行第一个可以运行的 Java 程序的时候都会要求写一个主函数. 然后很多人都会照葫芦画瓢的写一个下面的函数: public static void main(String[] args) ...

最新文章

  1. 码云gitee最大文件限制
  2. 计算机与USB沟通方式
  3. 科大星云诗社动态20210911
  4. mysql 无论输入什么都是现实 not found_NotAPanda
  5. 后“量子霸权”时代你不可错过的几本好书
  6. 吴恩达“旗下”Drive.ai无人出租车来了!新硬件成本更低,外挂4块屏幕
  7. Eclipse批量替换
  8. python中matplotlib 的简单使用
  9. oracle共享池的结构,Oracle 10g内存结构之共享池的相关知识及使用简介
  10. Grasshopper学习手册第二版资源
  11. rpg服务器修改数据,ATOM RPG 修改数据方法 怎么修改游戏数据-游侠网
  12. [转载]AdapterView.OnItemClickListener
  13. 电机控制基础之坐标变换(Clark变换及反变换 + Park变换及反变换 + 推导 + 仿真)
  14. pop3接收网易163邮件及下载超大附件
  15. python dataframe的某一列变为list_手把手教你用Python爬中国电影票房数据
  16. TARS 斩获 2018 年最佳原创开源软件奖
  17. acme.sh申请Let‘s encrypt泛域名证书Docker化部署
  18. Android网络开发技术实战详解
  19. [CocosCreator]热更新插件使用心得以及注意事项
  20. iOS 简单实用的音乐播放器,少年,自己做个歌单吧。。。。。。

热门文章

  1. 三月活动之“桃花朵朵开 求爱上上签”
  2. Binary XML file line #27: Error inflating class Listview
  3. 利用正则计算输入内容的长度
  4. 产品管理系列(一)---优秀的产品经理所具有的素质 王泽宾
  5. SuSE Linux 应用与安装
  6. 【转】VBScript-RegExp对象的详细用法
  7. web.config的问题
  8. CentOS 6.8下ELK+filebeat+redis 日志分析平台
  9. postgreSQL数据库默认用户postgres常用命令
  10. sftp配置导致ssh连接闪断