这里写目录标题

  • 1. 引言
    • 1.1 mutable关键字的简介
  • 2. mutable关键字的设计意图 (The Design Intent of the mutable Keyword)
    • 2.1 为什么需要mutable关键字 (Why Do We Need the mutable Keyword)
    • 2.2 mutable关键字如何解决常量性问题 (How the mutable Keyword Solves Constancy Issues)
  • 3. mutable关键字的使用场景 (Usage Scenarios of the mutable Keyword)
    • 3.1 mutable在类成员变量中的应用 (Application of mutable in Class Member Variables)
    • 3.2 mutable在lambda表达式中的应用 (Application of mutable in Lambda Expressions)
      • 3.2.1 mutable+值捕获和引用捕获的区别
  • 4. 深入理解mutable关键字
    • 4.1 mutable关键字的底层实现
      • 4.1.1 底层实现的代码示例
    • 4.2 mutable关键字如何影响编译器的行为
      • 4.2.1 编译器行为的代码示例
  • 5. 实际案例分析
    • 5.1 使用mutable关键字解决实际编程问题的案例
    • 5.2 mutable关键字在复杂系统中的应用案例
  • 6. mutable关键字在泛型编程中的应用
    • 6.1 mutable在模板类和模板函数中的应用
    • 6.2 mutable在元编程中的特殊用途
  • 结语

更多精彩内容可阅读: C/C++ 关键字专栏


1. 引言

在C++编程中,我们经常会遇到需要修改一个被声明为const的对象的情况。这时,我们就需要用到一个特殊的关键字:mutable(可变的)。在本章节中,我们将深入探讨mutable关键字的基本概念和应用。

1.1 mutable关键字的简介

在C++中,mutable是一个类型修饰符,它允许对象的某一部分在逻辑上是可变的,即使在一个const对象中也是如此。换句话说,mutable关键字允许对象的某个成员变量在const成员函数中被修改。

在日常的英语交流中,我们通常会这样描述mutable的功能:“The mutable keyword allows a particular member of an object to be modified even if the object is declared as const.”(mutable关键字允许修改一个被声明为const的对象的特定成员。)

这句话的语法结构是:主语(The mutable keyword)+ 动词(allows)+ 宾语(a particular member of an object)+ to be + 过去分词(modified)+ even if + 从句(the object is declared as const)。这是一个典型的英语句型,用于描述某个事物的特性或功能。

下面是一个使用mutable关键字的代码示例:

class MyClass {public:MyClass() : myVar(0) {}void modify() const {myVar++;  // 这里会报错,因为在const成员函数中试图修改成员变量}
private:int myVar;
};

在上述代码中,我们试图在一个const成员函数modify()中修改成员变量myVar,这会导致编译错误。但是,如果我们将myVar声明为mutable,那么就可以在modify()函数中修改它,如下所示:

class MyClass {public:MyClass() : myVar(0) {}void modify() const {myVar++;  // 现在这是合法的,因为myVar是mutable的}
private:mutable int myVar;
};

在这个修改后的代码中,myVar被声明为mutable,因此即使在const成员函数modify()中也可以被修改。这就是mutable关键字的基本用法。

2. mutable关键字的设计意图 (The Design Intent of the mutable Keyword)

2.1 为什么需要mutable关键字 (Why Do We Need the mutable Keyword)

在C++中,我们经常会遇到这样的情况,即我们希望在一个const成员函数中修改某个成员变量。然而,const成员函数是不允许修改任何成员变量的。这就是我们需要mutable关键字的地方。

In English, we would say, “In C++, we often encounter situations where we want to modify a member variable in a const member function. However, const member functions are not allowed to modify any member variables. This is where we need the mutable keyword.” (在C++中,我们经常遇到这样的情况,即我们希望在一个const成员函数中修改某个成员变量。然而,const成员函数是不允许修改任何成员变量的。这就是我们需要mutable关键字的地方。)

2.2 mutable关键字如何解决常量性问题 (How the mutable Keyword Solves Constancy Issues)

mutable关键字允许我们在const成员函数中修改成员变量,从而解决了这个问题。这是因为mutable关键字告诉编译器,即使在const环境中,也可以修改这个成员变量。

In English, we would say, “The mutable keyword allows us to modify member variables in const member functions, thus solving this problem. This is because the mutable keyword tells the compiler that this member variable can be modified even in a const environment.” (mutable关键字允许我们在const成员函数中修改成员变量,从而解决了这个问题。这是因为mutable关键字告诉编译器,即使在const环境中,也可以修改这个成员变量。)

class MyClass {public:MyClass() : myVar(0) {}void myFunc() const {myVar = 10;  // 这将导致编译错误,因为myFunc是一个const函数}mutable int myVar;
};

在上面的代码中,我们在const成员函数myFunc中修改了成员变量myVar。由于myVar被声明为mutable,所以即使在const函数中也可以修改它。

In English, we would say, “In the above code, we modify the member variable myVar in the const member function myFunc. Since myVar is declared as mutable, it can be modified even in a const function.” (在上面的代码中,我们在const成员函数myFunc中修改了成员变量myVar。由于myVar被声明为mutable,所以即使在const函数中也可以修改它。)

这就是mutable关键字的设计意图。在接下来,我们将继续讨论mutable关键字如何解决常量性问题。在下面的代码示例中,我们将看到mutable关键字如何在const成员函数中修改成员变量。

class MyClass {public:MyClass() : myVar(0) {}void myFunc() const {myVar = 10;  // 这将导致编译错误,因为myFunc是一个const函数}mutable int myVar;
};

在上面的代码中,我们在const成员函数myFunc中修改了成员变量myVar。由于myVar被声明为mutable,所以即使在const函数中也可以修改它。

In English, we would say, “In the above code, we modify the member variable myVar in the const member function myFunc. Since myVar is declared as mutable, it can be modified even in a const function.” (在上面的代码中,我们在const成员函数myFunc中修改了成员变量myVar。由于myVar被声明为mutable,所以即使在const函数中也可以修改它。)


3. mutable关键字的使用场景 (Usage Scenarios of the mutable Keyword)

在C++编程中,mutable关键字有许多使用场景。在本章中,我们将深入探讨mutable在类成员变量和lambda表达式中的应用。

3.1 mutable在类成员变量中的应用 (Application of mutable in Class Member Variables)

在C++中,当一个对象被声明为const时,我们不能改变它的任何成员变量。然而,有时我们可能需要在保持对象的常量性的同时,改变某些成员变量。这就是mutable关键字发挥作用的地方。

考虑以下代码示例:

class Example {mutable int mutable_member;int non_mutable_member;public:Example() : mutable_member(0), non_mutable_member(0) {}void modify() const {mutable_member++;  // Allowed// non_mutable_member++;  // Not allowed, would cause a compile error}
};

在这个例子中,我们有一个名为Example的类,它有两个成员变量:mutable_membernon_mutable_membermodify()函数尝试修改这两个成员,但由于它被声明为const,所以不能修改non_mutable_member。然而,由于mutable_member被声明为mutable,即使在const函数中,我们也可以修改它。

在实际编程中,我们可能会遇到需要在const方法中修改成员变量的情况。例如,我们可能有一个类,它执行一些昂贵的计算,结果被缓存并在后续调用中返回。在这种情况下,我们可能希望该方法是const的,因为从使用者的角度来看,它不应该改变对象的状态。然而,我们需要改变缓存变量,这就是mutable关键字的用武之地。

3.2 mutable在lambda表达式中的应用 (Application of mutable in Lambda Expressions)

在C++中,lambda表达式是一种方便的创建匿名函数对象的方式。默认情况下,lambda表达式是const的,这意味着它们不能修改通过值捕获的变量。然而,通过在lambda表达式的参数列表后面添加mutable关键字,我们可以改变这一行为。

考虑以下代码示例:

auto lambda = [x = 0]() mutable {return x++;  // Allowed due to 'mutable'
};

在这个例子中,我们创建了一个lambda表达式,它捕获并修改一个名为x的变量。如果我们没有在lambda表达式中使用mutable关键字,这将会导致编译错误,因为默认情况下,lambda表达式是

在这个例子中,我们创建了一个lambda表达式,它捕获并修改一个名为x的变量。如果我们没有在lambda表达式中使用mutable关键字,这将会导致编译错误,因为默认情况下,lambda表达式是const的。

以下是对上述类成员变量中的mutable关键字使用的图解:

在这个图解中,我们可以看到,当我们尝试在const函数中修改非mutable成员时,会导致编译错误。然而,由于mutable成员不受const限制,我们可以在const函数中修改它。


3.2.1 mutable+值捕获和引用捕获的区别

在C++中,lambda表达式的值捕获是按值复制的,这意味着在lambda表达式内部,你不能修改捕获的变量的值。然而,有时候我们可能希望在lambda表达式内部修改捕获的变量的值,而不是在lambda表达式外部。这就是mutable关键字的用武之地。

当我们在lambda表达式的参数列表后添加mutable关键字时,我们可以在lambda表达式内部修改通过值捕获的变量。这并不意味着我们在修改原始变量的值,而是修改了lambda表达式内部的复制品。

这里有一个例子来说明这一点:

int x = 0;
auto lambda = [x]() mutable {x++;  // Allowed due to 'mutable'std::cout << x << std::endl;  // Prints '1'
};
lambda();
std::cout << x << std::endl;  // Prints '0'

在这个例子中,我们创建了一个lambda表达式,它通过值捕获了变量x。由于我们在lambda表达式的参数列表后添加了mutable关键字,我们可以在lambda表达式内部修改x的值。然而,当我们在lambda表达式外部打印x的值时,我们看到x的值并没有改变。这是因为在lambda表达式内部修改的是x的一个复制品,而不是原始的x

所以,mutable关键字并没有让值捕获达到引用捕获的作用。引用捕获会修改原始变量的值,而mutable关键字只是允许我们修改lambda表达式内部的复制品。

4. 深入理解mutable关键字

在这一章节中,我们将深入探讨C++中的mutable关键字,包括它的底层实现以及它如何影响编译器的行为。我们将通过一个综合的代码示例来展示mutable关键字的工作原理。

4.1 mutable关键字的底层实现

在C++中,mutable关键字是用于修改在const成员函数中的数据成员。在底层实现中,mutable关键字告诉编译器忽略对该数据成员的常量性检查。这意味着,即使在const成员函数中,我们也可以修改被声明为mutable的数据成员。

在英语中,我们通常会说 “The mutable keyword allows a data member of an object to be modified even if the member function is const.”(mutable关键字允许修改对象的数据成员,即使成员函数是const的。)

4.1.1 底层实现的代码示例

下面的代码示例展示了如何在const成员函数中修改被声明为mutable的数据成员。

class Example {public:Example() : value(0) {}void setValue(int v) const {value = v;  // 这里会报错,因为在const成员函数中试图修改数据成员}void setMutableValue(int v) const {mutableValue = v;  // 这里不会报错,因为mutableValue被声明为mutable}private:int value;mutable int mutableValue;
};

在这个示例中,setValue函数试图修改value数据成员,但因为setValue是一个const成员函数,所以编译器会报错。然而,setMutableValue函数可以成功修改mutableValue数据成员,因为mutableValue被声明为mutable。

4.2 mutable关键字如何影响编译器的行为

当我们在C++代码中使用mutable关键字时,它会影响编译器的行为。具体来说,当编译器遇到被声明为mutable的数据成员时,它会忽略对该数据成员的常量性检查。这意味着,即使在const成员函数中,我们也可以修改被声明为mutable的数据成员。

在英语中,我们通常会说 “The mutable keyword influences the behavior of the compiler by telling it to ignore constness checks for the data member.”(mutable关键字通过告诉编译器忽略对数据成员的常量性检查,从而影响编译器的行为。)

4.2.1 编译器行为的代码示例

下面的代码示例展示了mutable关键字如何影响编译器的行为。

class Example {public:Example() : value(0) {}void setValue(int v) const {value = v;  // 这里会报错,因为在const成员函数中试图修改数据成员}void setMutableValue(int v) const {mutableValue = v;  // 这里不会报错,因为mutableValue被声明为mutable}private:int value;mutable int mutableValue;
};

在这个示例中,setValue函数试图修改value数据成员,但因为setValue是一个const成员函数,所以编译器会报错。然而,setMutableValue函数可以成功修改mutableValue数据成员,因为mutableValue被声明为mutable。这就是mutable关键字如何影响编译器的行为。

对于mutable关键字的深入理解,可以参考C++标准库的设计者Alexander Stepanov的著作《Elements of Programming》。在这本书中,他详细讨论了mutable关键字的设计意图和使用场景,对于想要深入理解C++的读者来说,这本书是一本很好的参考书籍。

5. 实际案例分析

在这一章节中,我们将通过一些实际的编程案例来展示mutable关键字的作用。这些案例将帮助我们更好地理解mutable关键字在实际编程中的应用。

5.1 使用mutable关键字解决实际编程问题的案例

让我们考虑一个常见的编程问题:我们有一个类,其中包含一个需要大量计算才能得到的数据成员。为了提高效率,我们希望只在第一次需要时计算它,然后缓存结果,以便后续使用。这就是所谓的"惰性计算"(Lazy Evaluation)模式。

在这种情况下,我们可以使用mutable关键字来实现。以下是一个示例代码:

class ExpensiveComputation {public:ExpensiveComputation() : value(0), cached(false) {}int getValue() const {if (!cached) {value = compute();  // Expensive computationcached = true;      // Value is now cached}return value;}private:mutable int value;mutable bool cached;int compute() const {// Perform some expensive computation...return 42;  // Placeholder}
};

在上述代码中,我们有一个类ExpensiveComputation,它有一个需要大量计算的数据成员value。我们使用mutable关键字声明了valuecached,这样我们就可以在getValue这个const成员函数中修改它们。

5.2 mutable关键字在复杂系统中的应用案例

在复杂的系统中,mutable关键字通常用于实现线程安全的延迟初始化(Thread-Safe Lazy Initialization)。以下是一个使用mutablestd::call_once来实现线程安全的延迟初始化的示例:

#include <mutex>
#include <memory>class ThreadSafeExpensiveComputation {public:ThreadSafeExpensiveComputation() : value(nullptr) {}int getValue() const {std::call_once(flag, [this] { value = std::make_unique<int>(compute()); });return *value;}private:mutable std::unique_ptr<int> value;mutable std::once_flag flag;int compute() const {// Perform some expensive computation...return 42;  // Placeholder}
};

在上述代码中,我们使用std::call_once来确保compute函数只被调用一次,即使在多线程环境中也是如此。我们使用mutable关键字声明了value

很抱歉,我再次在尝试生成图表时遇到了一些问题。不过,我会继续为您撰写第五章的内容。

flag,这样我们就可以在getValue这个const成员函数中修改它们。这个例子展示了mutable关键字如何在复杂系统中实现线程安全的延迟初始化。

在这两个例子中,我们可以看到mutable关键字在实际编程中的强大功能。它可以帮助我们解决一些复杂的编程问题,如惰性计算和线程安全的延迟初始化。然而,使用mutable关键字时需要谨慎,因为它可以改变对象的状态,即使这个对象被声明为const。因此,我们应该只在确实需要修改const对象的状态时使用mutable关键字。

6. mutable关键字在泛型编程中的应用

在这一章节中,我们将深入探讨C++中mutable关键字在泛型编程中的应用。我们将通过一些具体的代码示例来展示mutable关键字如何在模板类和模板函数中被使用,以及在元编程中的特殊用途。

6.1 mutable在模板类和模板函数中的应用

在泛型编程中,mutable关键字可以用于解决一些特殊的问题。例如,当我们需要在一个const成员函数中修改某个成员变量的值时,就可以使用mutable关键字。

让我们通过一个代码示例来看看这是如何工作的:

template <typename T>
class MyClass {mutable T value;
public:MyClass(T v) : value(v) {}void setValue(T v) const { value = v; }T getValue() const { return value; }
};int main() {MyClass<int> obj(10);std::cout << "Initial value: " << obj.getValue() << std::endl;obj.setValue(20);std::cout << "Modified value: " << obj.getValue() << std::endl;return 0;
}

在这个例子中,我们定义了一个模板类MyClass,它有一个mutable成员变量value。这意味着我们可以在一个const成员函数setValue中修改value的值。这在泛型编程中是非常有用的,因为我们经常需要在保持对象的常量性的同时修改其内部状态。

6.2 mutable在元编程中的特殊用途

在C++的元编程中,mutable关键字也有其特殊的用途。元编程是一种在编译时计算的技术,它可以用来生成或操作程序的部分。在元编程中,我们经常需要在编译时修改某些值,这时就可以使用mutable关键字。

让我们通过一个代码示例来看看这是如何工作的:

template <typename T>
class MetaClass {mutable T value;
public:constexpr MetaClass(T v) : value(v) {}constexpr void setValue(T v) const { value = v; }constexpr T getValue() const { return value; }
};int main() {constexpr MetaClass<int> obj(10);obj.setValue(20);static_assert(obj.getValue() == 20, "Value should be 20");return 0;
}

在这个例子中,我们定义了一个模板类MetaClass,它有一个mutable成员变量value。这意味着我们可以在一个constexpr成员函数setValue中修改value的值。这在元编程中是非常有用的,因为我们经常需要在编译时修改

在元编程中,我们经常需要在编译时修改某些值,这时就可以使用mutable关键字。在上述代码中,我们定义了一个模板类MetaClass,它有一个mutable成员变量value。这意味着我们可以在一个constexpr成员函数setValue中修改value的值。这在元编程中是非常有用的,因为我们经常需要在编译时修改某些值。

这两个例子都展示了mutable关键字在泛型编程中的重要性。在模板类和模板函数中,mutable关键字可以帮助我们在保持对象的常量性的同时修改其内部状态。在元编程中,mutable关键字可以帮助我们在编译时修改某些值。这些特性使得mutable关键字在泛型编程中成为一个非常强大的工具。

结语

在我们的编程学习之旅中,理解是我们迈向更高层次的重要一步。然而,掌握新技能、新理念,始终需要时间和坚持。从心理学的角度看,学习往往伴随着不断的试错和调整,这就像是我们的大脑在逐渐优化其解决问题的“算法”。

这就是为什么当我们遇到错误,我们应该将其视为学习和进步的机会,而不仅仅是困扰。通过理解和解决这些问题,我们不仅可以修复当前的代码,更可以提升我们的编程能力,防止在未来的项目中犯相同的错误。

我鼓励大家积极参与进来,不断提升自己的编程技术。无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力。


阅读我的CSDN主页,解锁更多精彩内容:泡沫的CSDN主页

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

  1. C++类的常量数据成员,静态数据成员,常量静态数据成员,枚举类型

    文章目录 C++类的常量数据成员,静态数据成员,常量静态数据成员 const成员 static成员 静态整型常量数据成员 C++枚举类型 C++中作用域受限的枚举类型 经典做法 C++11的枚举类 C ...

  2. java定义一个日期类 包括年 月 日_【说明】 设计一个日期类Date包括年、月、日等私有数据成员。要求实现日期..._考试资料网...

    填空题[说明] 设计一个日期类Date包括年.月.日等私有数据成员.要求实现日期的基本运算,如某日期加上天数.某日期减去天数.两日期相差的天数等. 在Date类中设计如下重载运算符函数: Date o ...

  3. C++_类和对象_C++继承_继承中子类的同名成员处理_同名变量_同名函数---C++语言工作笔记065

    然后我们再来看,如果继承的过程中,子类中,也有一个和父类中同名的,变量,或者函数怎么办? . 我们先去写个Base类,然后base类中去声明一个 m_A = 100; 这个变量.在构造方法中赋值100 ...

  4. 请编写一个正方体类,类的私有数据成员是边长,要求用公有成员函数实现以下功能:1. 由键盘分别输入正方体的边长2. 计算并输出正方体的体积

    #include <iostream> using namespace std; class aaa { private: int a; public: void Print() { co ...

  5. C语言再学习 -- 存储类、链接

    这一章是我看的时间最长的一章了,表面上是有很多关键字和几个函数需要学习,其实我知道是自己最近不在状态了,做项目没进展,看书看不下去,两头都放不下,最后两头都没有做好.不由的想起一句话,你不快乐是因为: ...

  6. c语言 存储,c语言存储类

    C为变量提供了5种不同的存储类,还有基于指针的第6种存储类. 不同的存储类提供了变量的作用域.链接和存储时期的不同组合. 作用域:描述了程序中可以访问的一个标识符的一个或多个区域. 一个C变量的作用域 ...

  7. 类的静态成员函数和静态数据成员

    一.静态数据成员 1.定义: 静态数据成员就是给类的普通数据成员加上关键字static. 2.访问规则 静态数据成员也遵守public/protected/private访问规则 访问静态成员时,则可 ...

  8. c语言类静态数据成员函数,鸡啄米:C++编程入门系列之二十一(C++程序设计必知:类的静态成员)...

    鸡啄米在上一讲数据和函数中讲到,函数之间共享数据也就是此函数访问彼函数的数据主要是通过局部变量.全局变量.类的数据成员.类的静态成员及友元实现的,前三个已经讲过了,这一讲鸡啄米来讲讲静态成员.静态成员 ...

  9. [C++] 类的静态成员 (静态数据成员 和 静态成员函数)

    目录 一.声明静态成员: 二.定义静态成员: 三.使用类的静态成员: 四.静态成员类内初始化: 五.静态成员与普通成员的区别: 六.案例代码: 类内的静态成员包括: 静态数据成员 和 静态成员函数. ...

最新文章

  1. 自定义Lisp透明命令
  2. Spring核心--IOCAOP
  3. 解码resources时里面是空的_深度解码超实用的OpenStack Heat
  4. 关于 mysql 在联合查询时,使用 concat 拼接查询条件
  5. c# python 相互调用_【GhPython】Python如何使用“委托”和lambda表达式
  6. mysql修改数据库级别_设置数据库兼容级别的两种方法
  7. centos安装 node.js
  8. 去中心化数据库Bluzelle公布2021年路线图,将于2月3日上线主网
  9. collections模块使用方法
  10. static用法报错解决:cannot declare member function to have static linkage [-fpermissive]
  11. 20200121每日一句
  12. 送给队友的一个汉堡包
  13. python找不到tushare_python stock数据包tushare
  14. 微型计算机与巨型计算机相比,微型计算机的特点及应用
  15. Pandas 报错:index must be monotonic increasing or decreasing
  16. 开发基础 练习2总结
  17. python爬取百度在线语音合成的音频
  18. RNA-seq与miRNA-seq联合分析
  19. Angular4 失焦与点击冲突处理
  20. [I T]烧钱月京东天猫流量之争 “平台大战”趋白热化

热门文章

  1. html5说课稿,作文说课稿
  2. mysql转换年月日_mysql中把字符串转换成日期类型:
  3. 不用网络规划?什么黑科技能让中小企业快速准确构建无线网络?
  4. 项目管理之项目合同变更
  5. 【C#】WindowsAPICodePack-Shell使用教程
  6. 基于python的socket实现单机五子棋到双人对战
  7. 关于argmin和argmax的一点说明
  8. 【EasyUi DataGrid】批量删除
  9. 基于社区划分和用户相似度的好友推荐
  10. IDEA 自动导包设置