为何调用`operator=`时自动传入`const stsb::promise<int>`类型的`this`?
问题分析与解决:promise类赋值时的const限定错误
问题代码
主程序代码
#include "promise.hpp" #include <thread> using namespace std; int main() { stsb::promise<int> tstint = stsb::promise<int>(); thread waitthr = thread([tstint]() { // do some work tstint = 27; }); waitthr.detach(); // wait for result and do smth with it }
stsb::promise模板类代码
#include <mutex> #include <optional> #include <memory> namespace stsb { template<typename T> class promise { private: std::shared_ptr<T> storage; std::shared_ptr<bool> ready; std::mutex mtx; public: inline promise(T& storage) : storage(std::make_shared<T>(storage)), ready(new bool(false)), mtx() {} inline promise(void) : storage(new T()), ready(new bool(false)), mtx() {} inline promise(const promise& cp) : storage(cp.storage), ready(cp.ready), mtx() {} inline promise(promise&& cp) : storage(cp.storage), ready(cp.ready), mtx() {} inline promise<T>& operator=(T&& value) { mtx.lock(); *(storage.get()) = value; mtx.unlock(); *(ready.get()) = true; return *this; } inline std::optional<T> operator()() { mtx.lock(); if (!(*(ready.get()))) { mtx.unlock(); return std::nullopt; } auto tmp = *(storage.get()); mtx.unlock(); return tmp; } inline ~promise() {} }; }
错误信息
error: passing 'const stsb::promise<int>' as 'this' argument discards qualifiers [-fpermissive]
错误出现在tstint = 27;这一行。
错误原因
默认情况下,lambda表达式的operator()是const成员函数,按值捕获的tstint在lambda内部会被视为const对象。而你的promise<T>::operator=(T&&)是非const成员函数,C++不允许在const对象上调用非const成员函数,因此触发了这个错误。
解决方案
1. 按引用捕获对象(推荐)
将lambda的捕获方式改为引用捕获,这样内部操作的就是原对象,而非const副本:
thread waitthr = thread([&tstint]() { // do some work tstint = 27; });
注意:由于线程使用了detach(),必须保证main函数不会在线程执行完毕前退出,否则原对象tstint会被销毁,导致线程访问悬空引用。
2. 让lambda变为mutable(不推荐此场景)
如果坚持按值捕获,可以给lambda加上mutable修饰符,这样lambda的operator()会失去const限定,内部的tstint就可以被修改:
thread waitthr = thread([tstint]() mutable { // do some work tstint = 27; });
但这种方式修改的是lambda内部的tstint副本,原对象不会被更新,完全不符合你用promise传递结果的需求,因此不建议使用。
3. 额外优化:修复promise类的mutex使用问题
你的promise类中直接调用mtx.lock()和mtx.unlock()存在风险——如果赋值过程中抛出异常,mutex会一直处于锁定状态,导致死锁。应该用RAII工具std::lock_guard自动管理锁的生命周期:
inline promise<T>& operator=(T&& value) { std::lock_guard<std::mutex> lock(mtx); *storage = std::move(value); *ready = true; return *this; } inline std::optional<T> operator()() { std::lock_guard<std::mutex> lock(mtx); if (!*ready) { return std::nullopt; } return *storage; }
内容的提问来源于stack exchange,提问作者Stas Badzi
相关产品推荐
相关产品推荐

