错误的代码如下:
#include <iostream>
#include <cassert>
#include <mutex>
#include <condition_variable>
template <typename T>
class CircularQueue {
private:
T* data; // 数据存储数组
int capacity; // 队列容量
int head; // 队首指针
int tail; // 队尾指针
int count; // 当前元素数量
std::mutex mtx; // 互斥锁
std::condition_variable not_full; // 队列未满条件变量
std::condition_variable not_empty; // 队列非空条件变量
public:
// 构造函数
explicit CircularQueue(int cap) : capacity(cap), head(0), tail(0), count(0) {
if (cap <= 0) throw std::invalid_argument("Capacity must be positive");
data = new T[cap];
}
// 析构函数
~CircularQueue() {
delete[] data;
}
// 入队操作(支持超时)
bool enqueue(const T& item, int timeout_ms = 0) {
std::unique_lock<std::mutex> lock(mtx);
// 等待队列未满(带超时)
if (!not_full.wait_for(lock, std::chrono::milliseconds(timeout_ms),
[this] { return count < capacity; })) {
return false; // 超时返回失败
}
data[tail] = item;
tail = (tail + 1) % capacity;
++count;
not_empty.notify_one(); // 通知消费者
return true;
}
// 出队操作(支持超时)
bool dequeue(T& item, int timeout_ms = 0) {
std::unique_lock<std::mutex> lock(mtx);
// 等待队列非空(带超时)
if (!not_empty.wait_for(lock, std::chrono::milliseconds(timeout_ms),
[this] { return count > 0; })) {
return false; // 超时返回失败
}
item = data[head];
head = (head + 1) % capacity;
--count;
not_full.notify_one(); // 通知生产者
return true;
}
// 获取队列当前元素数量
int size() const {
std::lock_guard<std::mutex> lock(mtx);
return count;
}
// 判断队列是否为空
bool isEmpty() const {
std::lock_guard<std::mutex> lock(mtx);
return count == 0;
}
// 判断队列是否已满
bool isFull() const {
std::lock_guard<std::mutex> lock(mtx);
return count == capacity;
}
};
error
上面的代码std::lock_guardstd::mutex lock(mtx);在运行时会出现报错:
在编译时出现error C2665: “std::lock_guardstd::mutex::lock_guard”: 没有重载函数可以转换所有参数类型
这个编译错误的原因是:在 const
成员函数中使用了非 mutable
的互斥锁。std::lock_guard
的构造函数需要接受一个非 const 的互斥锁引用,而 const
成员函数中的成员变量默认被视为 const
。
解决方案
将 mtx
声明为 mutable
:
template <typename T>
class CircularQueue {
private:
// 其他成员...
mutable std::mutex mtx; // 添加 mutable 修饰符
// ...
};
错误原因详解
-
const
成员函数的限制
在const
成员函数(如isFull()
)中,所有非mutable
的成员变量默认被视为const
。因此,mtx
会被视为const std::mutex
。 -
lock_guard
的构造函数要求
std::lock_guard
的构造函数接受的是普通(非 const)互斥锁引用:explicit lock_guard(mutex_type& m); // 需要 mutex 的非 const 引用
-
类型不匹配
在const
函数中,mtx
的类型是const std::mutex
,无法转换为std::mutex&
,导致编译错误。
修正后的代码片段
template <typename T>
class CircularQueue {
private:
T* data;
int capacity;
int head;
int tail;
int count;
mutable std::mutex mtx; // 声明为 mutable
std::condition_variable not_full;
std::condition_variable not_empty;
public:
// ...
// 判断队列是否已满(const 函数)
bool isFull() const {
std::lock_guard<std::mutex> lock(mtx); // 现在可以编译通过
return count == capacity;
}
};
关键知识点
-
mutable
关键字的作用- 允许在
const
成员函数中修改被标记为mutable
的成员变量。 - 适用于需要逻辑上为
const
但物理上需要修改的场景(如互斥锁、缓存等)。
- 允许在
-
线程安全与
const
的协同
即使对象是const
的,线程安全操作(如加锁)仍然需要物理上的状态修改,因此互斥锁应声明为mutable
。 -
lock_guard
的正确使用- 在需要加锁的成员函数中(无论是否
const
),使用mutable
修饰互斥锁。 - 确保所有访问共享数据的操作都通过锁保护。
- 在需要加锁的成员函数中(无论是否
其他可能的相关问题
如果遇到类似错误(如 error C2665
或 no matching constructor
),检查:
- 是否在
const
函数中未正确使用mutable
。 - 是否误传了互斥锁的副本而非引用(如
std::mutex
不可复制)。 - 头文件是否包含完整(
#include <mutex>
)。
通过声明 mtx
为 mutable
,该编译错误应被解决。