C++中的常量(const)与可变成员(mutable)详解
·
C++中的常量(const)与可变成员(mutable)详解
1. const关键字

1.1 基本概念
const是C++中的类型修饰符,用于定义不可修改的对象或变量。一旦被const修饰,该变量的值在初始化后就不能被改变。
1.2 const的不同用法
1.2.1 const变量
const int MAX_SIZE = 100;
const double PI = 3.14159;
// MAX_SIZE = 200; // 错误:不能修改const变量
1.2.2 const指针
int value = 10;
int another = 20;
// 指向常量的指针
const int* ptr1 = &value;
// *ptr1 = 30; // 错误:不能通过ptr1修改value
ptr1 = &another; // 正确:可以改变指针指向
// 常量指针
int* const ptr2 = &value;
*ptr2 = 30; // 正确:可以通过ptr2修改value
// ptr2 = &another; // 错误:不能改变指针指向
// 指向常量的常量指针
const int* const ptr3 = &value;
// *ptr3 = 30; // 错误:不能修改指向的值
// ptr3 = &another; // 错误:不能改变指针指向
1.2.3 const成员函数
class MyClass {
private:
int data;
mutable int accessCount; // 可以使用mutable修饰
public:
MyClass(int d) : data(d), accessCount(0) {}
// const成员函数 - 承诺不修改对象状态
int getData() const {
// data = 100; // 错误:const成员函数不能修改成员变量
accessCount++; // 正确:mutable成员可以在const函数中修改
return data;
}
// 非const成员函数
void setData(int d) {
data = d;
}
// const重载
void display() const {
std::cout << "Data: " << data << std::endl;
}
void display() {
std::cout << "Non-const Data: " << data << std::endl;
}
};
1.2.4 const对象
const MyClass obj(42);
obj.getData(); // 正确:可以调用const成员函数
// obj.setData(100); // 错误:不能调用非const成员函数
1.3 const在函数参数中的使用
// 传递const引用,避免拷贝同时保证不修改原对象
void printVector(const std::vector<int>& vec) {
for (const auto& elem : vec) {
std::cout << elem << " ";
}
// vec.push_back(10); // 错误:不能修改const引用
}
// 返回const值,防止返回值被修改
const std::string createGreeting() {
return "Hello, World!";
}
2. mutable关键字
2.1 基本概念
mutable用于修饰类的成员变量,表示即使对象是const的,这个成员变量也可以被修改。
2.2 mutable的使用场景
2.2.1 缓存和惰性求值
class ExpensiveCalculation {
private:
mutable double cachedValue;
mutable bool isCached;
int input;
public:
ExpensiveCalculation(int i) : input(i), isCached(false), cachedValue(0) {}
double getResult() const {
if (!isCached) {
// 模拟昂贵计算
cachedValue = std::sqrt(input * 2.0 + 1.0);
isCached = true;
}
return cachedValue;
}
};
2.2.2 访问计数
class AccessCounter {
private:
int data;
mutable int readCount;
mutable int writeCount;
public:
AccessCounter(int d) : data(d), readCount(0), writeCount(0) {}
int getData() const {
readCount++;
return data;
}
void setData(int d) {
writeCount++;
data = d;
}
void showStats() const {
std::cout << "Reads: " << readCount << ", Writes: " << writeCount << std::endl;
}
};
2.2.3 线程安全
#include <mutex>
class ThreadSafeCounter {
private:
mutable std::mutex mtx;
int count;
public:
ThreadSafeCounter() : count(0) {}
int getCount() const {
std::lock_guard<std::mutex> lock(mtx);
return count;
}
void increment() {
std::lock_guard<std::mutex> lock(mtx);
count++;
}
};
2.3 mutable的注意事项
class Example {
private:
mutable int counter;
int importantData;
public:
Example() : counter(0), importantData(42) {}
// 错误使用mutable的例子 - 破坏了逻辑常量性
void badConstFunction() const {
counter++; // 正确:mutable可以修改
// importantData = 100; // 错误:不能修改非mutable成员
// 虽然语法上允许,但逻辑上不应该这样做
// 因为这会改变对象的逻辑状态
}
};
3. const和mutable的结合使用
3.1 实际应用示例
class DatabaseConnection {
private:
mutable std::mutex connectionMutex;
mutable bool isConnected;
mutable std::string connectionInfo;
const std::string serverAddress;
public:
DatabaseConnection(const std::string& address)
: serverAddress(address), isConnected(false) {}
// const函数,但可以修改mutable成员
bool checkConnection() const {
std::lock_guard<std::mutex> lock(connectionMutex);
if (!isConnected) {
// 模拟连接操作
isConnected = true;
connectionInfo = "Connected to " + serverAddress;
}
return isConnected;
}
// 可以访问serverAddress,但不能修改(因为是const)
std::string getServerAddress() const {
return serverAddress;
}
};
3.2 智能指针与const/mutable
class ResourceManager {
private:
mutable std::shared_ptr<Resource> cachedResource;
mutable std::mutex resourceMutex;
public:
std::shared_ptr<Resource> getResource() const {
std::lock_guard<std::mutex> lock(resourceMutex);
if (!cachedResource) {
cachedResource = std::make_shared<Resource>();
}
return cachedResource;
}
};
4. 最佳实践和注意事项
4.1 const正确性原则
- 默认使用const:如果变量不需要修改,应该声明为const
- 参数传递:对于不会修改的参数,使用const引用
- 成员函数:不修改对象状态的成员函数应该声明为const
- 返回值:如果返回值不应该被修改,返回const类型
4.2 mutable的使用准则
- 仅用于不影响对象逻辑状态的成员
- 避免在mutable成员中存储重要业务数据
- 主要用于技术性状态(缓存、计数器、锁等)
- 确保线程安全性
4.3 示例:良好的设计
class Configuration {
private:
mutable std::mutex configMutex;
mutable std::unordered_map<std::string, std::string> cache;
std::unordered_map<std::string, std::string> settings;
public:
// const函数,使用mutable实现缓存
std::string getSetting(const std::string& key) const {
std::lock_guard<std::mutex> lock(configMutex);
// 检查缓存
auto cacheIt = cache.find(key);
if (cacheIt != cache.end()) {
return cacheIt->second;
}
// 从设置中获取并缓存
auto settingIt = settings.find(key);
if (settingIt != settings.end()) {
cache[key] = settingIt->second;
return settingIt->second;
}
return "";
}
// 非const函数,修改设置并清除缓存
void setSetting(const std::string& key, const std::string& value) {
std::lock_guard<std::mutex> lock(configMutex);
settings[key] = value;
cache.clear(); // 清除缓存,因为设置已改变
}
};
总结
const和mutable是C++中用于控制对象可变性的重要工具:
- const提供编译时的常量性保证,增强代码的安全性和可读性
- mutable在保持逻辑常量性的同时,允许修改技术性状态
- 合理使用这两个关键字可以写出更安全、更清晰、更高效的代码
正确理解和使用const和mutable是成为优秀C++程序员的重要一步,它们帮助我们在编译期捕获错误,同时提供必要的灵活性来处理现实世界的编程需求。
(注:文档部分内容可能由 AI 生成)
更多推荐


所有评论(0)