【C/C++ 学习】mutable关键字

mutable关键字

🌞偶然碰见了mutable,然后学习记录一下
总结一下就是打破const成员函数不能修改成员变量的壁垒,而又想在这个函数里面使用可变的变量。

1. mutable 的核心作用

A. 规则:const 成员函数不能修改成员变量

在 C++ 中,如果一个成员函数被声明为 const,例如:

bool empty() const { /* ... */ } // 注意这里的 const

这表示这个函数不会修改对象的任何成员变量。因此,编译器会阻止你在 const 函数中修改任何非 mutable 的成员变量。

B. mutable 的豁免权

将一个成员变量声明为 mutable,就像给它颁发了一个豁免证。它允许该变量在对象的常量成员函数中被修改。

例如 SafeQueue 代码中,mutable 是用在 empty() 函数上:

// SafeQueue.h
private:
    queue<T> q;
    mutable mutex m; // <--- 关键在这里
    condition_variable c;

public:
    // ...
    bool empty(){ // 注意:这个函数没有被声明为 const!
        lock_guard<mutex> lock(m);
        return q.empty();
    };

例子🌰

🌰下面举个例子:

假设我们要创建一个线程安全的计数器,并希望对外提供一个 const 的获取计数函数。

1. 错误的尝试 (没有 mutable)

如果我们不使用 mutable,并且尝试将 getCount() 声明为 const

#include <mutex>
#include <iostream>

class DataTracker_Error {
private:
    int data_count = 0;
    std::mutex m; // ❌ 错误:不是 mutable

public:
    void increment() {
        std::lock_guard<std::mutex> lock(m);
        data_count++;
    }

    // 尝试声明为 const 函数
    int getCount() const { 
        // 🚨 编译错误!因为 lock_guard 会调用 m.lock(),
        // 而 m.lock() 会改变 m 的状态,违反了 getCount() 的 const 承诺。
        std::lock_guard<std::mutex> lock(m); 
        return data_count;
    }
};

编译结果: 编译器会报错,因为它发现你在一个 const 函数中试图修改一个非 mutable 的成员变量 m

2. 正确的实现 (使用 mutable)

为了让 const 函数 能够进行线程同步操作(即锁定互斥锁),我们必须将互斥锁声明为 mutable

#include <mutex>
#include <iostream>
#include <thread>

class DataTracker_Correct {
private:
    int data_count = 0;
    mutable std::mutex m; // ✅ 正确:使用 mutable 关键字

public:
    void increment() {
        std::lock_guard<std::mutex> lock(m);
        data_count++;
    }

    // getCount() 是 const 函数,但由于 m 是 mutable,所以可以锁定它。
    int getCount() const { 
        // 逻辑上:getCount 只是读取数据,没有改变对象的数据状态。
        // 物理上:它需要改变 m 的内部状态(锁定/解锁)。
        std::lock_guard<std::mutex> lock(m); 
        return data_count;
    }
};

// 示例用法
int main() {
    DataTracker_Correct tracker;
    
    // 我们可以用一个 const 引用来调用 getCount()
    const DataTracker_Correct& const_tracker = tracker;
    
    // 这行代码可以编译通过并安全执行,因为它在 const 函数中使用了 mutable 锁。
    std::cout << "Current count: " << const_tracker.getCount() << std::endl; 
    
    return 0;
}

在这个例子中:

  • 逻辑状态getCount() 不改变 data_count,所以它被认为是 const 的。
  • 物理状态std::mutex m 的内部状态(锁定/解锁)在 getCount() 中必须被改变。
  • mutable 的作用:它打破了 const 函数不能修改成员变量的限制,允许我们在保持逻辑常量性的同时,执行线程安全所需的底层同步操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~光~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值