C++mutable

embedded/2024/9/24 12:24:19/

文章目录

  • Claude 讲解
    • 基本用法
    • mutable的常见用途
    • 注意事项
  • ChatGpt 讲解
      • 1. 基本概念
      • 2. 使用示例
        • 解释:
      • 3. 适用场景
      • 4. 注意事项
    • lambda 讲解
      • 基本语法
      • 示例
      • 捕获方式
      • 使用场景
    • mutable 和 labmda 一起使用
      • 代码:
      • 代码分析:
      • 输出结果:

在C++编程中, const关键字通常用于保证对象的不可变性,从而提高代码的安全性和可维护性。然而,有时我们会遇到这样的需求:希望在某些特定的成员变量上保留修改的灵活性,即使它们属于一个 const对象。为了解决这个矛盾,C++提供了 mutable关键字,它允许我们在严格遵守 const约束的同时,依然能够修改某些特定的成员变量。本文将带你深入探讨 mutable的使用场景及其应用。

Claude 讲解

mutable是C++中的一个关键字,用于修饰类的成员变量。它的主要作用是允许在const成员函数中修改被mutable修饰的成员变量。这打破了const成员函数不能修改对象状态的一般规则。

让我们通过几个例子来理解mutable的用法:

基本用法

class Counter {
private:mutable int count = 0;public:void increment() const {++count;  // 可以在const函数中修改mutable成员}int getCount() const {return count;}
};int main() {const Counter c;c.increment();  // 合法,尽管c是const对象std::cout << c.getCount();  // 输出1return 0;
}

在这个例子中,尽管increment()是一个const成员函数,但它仍然可以修改count成员,因为count被声明为mutable。

mutable的常见用途

mutable通常用于以下场景:

a) 缓存: 当某个计算很昂贵,我们想在const对象中缓存结果时。

b) 互斥锁: 在多线程环境中,即使对象是const的,我们也可能需要锁定资源。

c) 计数器或统计信息: 如上面的例子所示。

注意事项

  • 过度使用mutable可能会导致代码难以理解和维护。
  • mutable不应该用来绕过const的语义,而应该用于那些不影响对象逻辑状态的情况。

ChatGpt 讲解

在C++中,mutable关键字用于允许类的某些成员变量在常量对象中被修改。通常情况下,当你声明一个对象为常量(即使用const关键字),这个对象的所有成员都不允许被修改。但在某些情况下,你可能希望某些成员能够在常量对象中被修改,此时就可以使用mutable关键字。

1. 基本概念

当一个类的成员被声明为mutable时,即使对象是const的,也允许该成员被修改。mutable关键字通常用于标识那些不影响对象逻辑状态的成员变量,例如用于缓存、计数器等。

2. 使用示例

以下是一个简单的示例,展示了mutable关键字的用法:

#include <iostream>class Counter {
private:mutable int counter = 0; // 使用 mutable 关键字
public:void increment() const {counter++; // 即使在 const 方法中,mutable 变量也可以被修改}int getCounter() const {return counter;}
};int main() {const Counter c;c.increment();std::cout << "Counter: " << c.getCounter() << std::endl; // 输出: Counter: 1return 0;
}
解释:
  • 在上面的代码中,Counter类中包含一个私有成员变量counter,它被声明为mutable
  • increment方法被声明为const,这意味着它不能修改对象的状态。然而,由于counter被声明为mutable,它仍然可以在increment方法中被修改。
  • 最终,main函数中的c.increment()可以成功地增加counter的值,即使c本身是一个常量对象。

3. 适用场景

  • 缓存机制:当你想在一个const成员函数中修改一些缓存数据,而这些数据对类的逻辑状态没有影响时,可以使用mutable
  • 日志记录:当你在一个const成员函数中想记录一些日志信息,并且需要修改日志数据时,可以使用mutable

4. 注意事项

  • mutable只能用于非静态成员变量。
  • mutable并不会绕过const的保护机制;它仅允许特定成员变量在const对象中被修改,因此应谨慎使用,确保不会误修改对象的逻辑状态。

mutable关键字在C++中为管理对象的可变性提供了更大的灵活性,尤其是在需要处理类似缓存或日志记录的场景时非常有用。
在这里插入图片描述

在这里插入图片描述

lambda 讲解

在C++中,lambda表达式是一种可以在本地定义匿名函数的方式。它们在C++11标准中被引入,并且在C++14和C++17中得到了进一步的扩展。lambda表达式非常适合用于需要在短时间内定义并使用函数的情况,比如在STL算法中作为回调函数。

基本语法

一个lambda表达式的基本语法如下:

[capture](parameters) -> return_type {// function body
};
  • capture:捕获列表,用于指定lambda表达式可以使用哪些外部变量。
  • parameters:参数列表,类似于普通函数的参数列表。
  • return_type:返回类型(可选,如果可以从函数体推断出返回类型,则可以省略)。
  • function body:函数体,包含实际执行的代码。

示例

  1. 简单的lambda表达式:
auto add = [](int a, int b) {return a + b;
};int result = add(3, 4); // result = 7
  1. 带捕获列表的lambda表达式:
int x = 10;
int y = 20;auto add_with_capture = [x, y](int a) {return a + x + y;
};int result = add_with_capture(5); // result = 35
  1. 捕获所有外部变量:
int x = 10;
int y = 20;auto add_all = [=](int a) {return a + x + y;
};int result = add_all(5); // result = 35
  1. 捕获外部变量的引用:
int x = 10;auto increment = [&x]() {++x;
};increment();
std::cout << x; // 输出 11
  1. 指定返回类型:
auto divide = [](int a, int b) -> double {if (b == 0) return 0;return static_cast<double>(a) / b;
};double result = divide(10, 3); // result = 3.33333

捕获方式

捕获列表可以使用多种方式来捕获变量:

  • [x, &y]:按值捕获x,按引用捕获y。
  • [=]:按值捕获所有外部变量。
  • [&]:按引用捕获所有外部变量。
  • [this]:捕获当前对象的this指针(隐式捕获对象的成员)。

使用场景

lambda表达式在很多情况下都非常有用,尤其是在使用STL(标准模板库)的算法时。例如:

std::vector<int> numbers = {1, 2, 3, 4, 5};
std::for_each(numbers.begin(), numbers.end(), [](int &n) { n *= 2; });
// numbers 现在包含 {2, 4, 6, 8, 10}

在这里插入图片描述

mutable 和 labmda 一起使用

代码:

#include <iostream>
#include <string>class Entity {
public:std::string GetName() const {return "EntityName";}
};int main() {const Entity e; // 常量对象estd::cout << e.GetName() << std::endl; // 调用GetName并打印int x = 8; // 定义变量xauto f = [=]() mutable { // 使用lambda表达式捕获xx++; // 因为lambda是mutable的,所以可以修改捕获的xstd::cout << "x after increment: " << x << std::endl;};f(); // 调用lambda表达式return 0;
}

代码分析:

  1. Entity类的定义

    class Entity {
    public:std::string GetName() const {return "EntityName";}
    };
    
    • 这里定义了一个Entity类,包含一个名为GetName的成员函数,该函数返回一个字符串。
    • GetName函数被声明为const,意味着它不能修改对象的状态。
  2. main函数

    const Entity e;
    std::cout << e.GetName() << std::endl;
    
    • e是一个const Entity对象。
    • std::cout打印了e.GetName()的返回值。
  3. lambda表达式

    int x = 8;
    auto f = [=]() mutable {x++;std::cout << "x after increment: " << x << std::endl;
    };
    
    • int x = 8; 声明了一个整数变量x并赋值为8
    • auto f = [=]() mutable {...}; 定义了一个lambda表达式:
      • [=]:捕获x的值(通过值捕获)。
      • mutable:允许修改捕获的值(通常通过值捕获的变量在lambda中是只读的,使用mutable后可以修改它)。
      • x++:在lambda内部递增x
      • std::cout << ... 打印修改后的x
  4. 调用lambda

    f();
    
    • 调用lambda表达式f,输出x的值,应该是9

输出结果:

EntityName
x after increment: 9

这个例子展示了const对象如何调用const成员函数,以及mutable关键字在lambda表达式中的作用,使得捕获的值可以被修改。


http://www.ppmy.cn/embedded/109903.html

相关文章

uniapp个人健康预警管理系统 微信小程序的设计与实现 38vk1

目录 博主介绍技术栈系统设计&#x1f31f;文末获取源码数据库&#x1f31f;具体实现截图后端前端java类核心代码部分展示可行性论证个人心得系统测试操作可行性源码获取详细视频演示 博主介绍 &#x1f447;&#x1f3fb; 博主介绍&#xff1a;&#x1f447;&#x1f3fb; 专…

PyTorch自动混合精度训练

torch.cuda.amp.GradScaler 是 PyTorch 中的一个用于自动混合精度&#xff08;Automatic Mixed Precision, AMP&#xff09;训练的工具。AMP 允许在训练深度学习模型时动态切换浮点数的精度&#xff08;例如&#xff0c;使用半精度浮点数 float16 而非 float32&#xff09;&…

非监督式机器学习:群集

聚类分析是一种非监督式机器学习形式&#xff0c;在此形式下&#xff0c;基于观察值的数据值或特征的相似性&#xff0c;将观察值分组到群集中。 这种就是非监督式机器学习&#xff0c;因为它不使用先前已知的标签值来训练模型。 在聚类分析模型中&#xff0c;标签是群集&#…

Java设计模式【备忘录模式】-行为型

1. 介绍 备忘录模式&#xff08;Memento Pattern&#xff09; 是一种行为型设计模式&#xff0c;允许在不破坏封装的前提下&#xff0c;捕获并保存一个对象的内部状态&#xff0c;然后可以在以后将其恢复到原先保存的状态。备忘录模式的核心思想是记录和恢复对象的状态&#x…

Catia的插件不能调用CAA 的API问题

今天到客户实施Catia二开软件&#xff0c;发现在客户的电脑上调用CAA的API出现调用失败的问题。 根据经验&#xff0c;想到大概是用户电脑上的Catia授权有问题&#xff0c;但是Catia的一大堆授权中需要哪些授权呢&#xff0c;最后花了半天的时间使用二分法测试出&#xff0c;C…

VS2010程序打包为可执行安装程序

说明 记录一下下次再用时省点事儿&#xff0c;直接进入正题吧 步骤 1. 首先把该装好的软件装好&#xff0c;然后创建一个 安装项目 , 如下图 2. 右键 应用程序文件夹 的 添加 , 如下图可添加要打包的文件(和文件夹&#xff0c;文件夹需要添加文件夹)&#xff0c;一般是已经编…

前后端时间传递之注解

一、前言 前后端进行数据交互时&#xff0c;对于时间总会出现问题&#xff0c;今天我们来总结一下这么解决。 二、前端传后端&#xff08;DateTimeFormat&#xff09; 前端给后端传递时间参数的时候传递的都是String类型的数据&#xff0c;后端如果用数据库类型Date来接收的…

结构开发笔记(七):solidworks软件(六):装配摄像头、摄像头座以及螺丝,完成摄像头结构示意图

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/141931518 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…