为何无法为std::optional<std::lock_guard>执行赋值操作?
为什么
std::optional<std::lock_guard>无法后续赋值,而std::optional<std::string>可以? 你会发现下面的代码可以正常运行:
std::mutex m; std::optional<std::lock_guard<std::mutex>> lg(m);
但以下两段代码均无法运行:
代码(*)
std::mutex m; std::optional<std::lock_guard<std::mutex>> lg; lg = std::lock_guard<std::mutex>(m);
报错信息:
1>c:\foo.cpp(51): error C2679: binary '=': no operator found which takes a right-hand operand of type 'std::lock_guard<std::mutex>' (or there is no acceptable conversion) 1>c:\program files (x86)\microsoft visual studio\2017\professional\vc\tools\msvc\14.13.26128\include\optional(547): note: could be 'std::optional<std::lock_guard<std::mutex>> &std::optional<std::lock_guard<std::mutex>>::operator =(const std::optional<std::lock_guard<std::mutex>> &)' 1>c:\program files (x86)\microsoft visual studio\2017\professional\vc\tools\msvc\14.13.26128\include\optional(320): note: or 'std::optional<std::lock_guard<std::mutex>> &std::optional<std::lock_guard<std::mutex>>::operator =(std::nullopt_t) noexcept' 1>c:\foo.cpp(51): note: while trying to match the argument list '(std::optional<std::lock_guard<std::mutex>>, std::lock_guard<std::mutex>)'
代码(**)
std::mutex m; std::optional<std::lock_guard<std::mutex>> lg; lg = std::optional<std::lock_guard<std::mutex>>(m);
报错信息:
1>c:\foo.cpp(51): error C2280: 'std::optional<std::lock_guard<std::mutex>> &std::optional<std::lock_guard<std::mutex>>::operator =(const std::optional<std::lock_guard<std::mutex>> &)': attempting to reference a deleted function 1>c:\program files (x86)\microsoft visual studio\2017\professional\vc\tools\msvc\14.13.26128\include\optional(547): note: compiler has generated 'std::optional<std::lock_guard<std::mutex>>::operator =' here 1>c:\program files (x86)\microsoft visual studio\2017\professional\vc\tools\msvc\14.13.26128\include\optional(547): note: 'std::optional<std::lock_guard<std::mutex>> &std::optional<std::lock_guard<std::mutex>>::operator =(const std::optional<std::lock_guard<std::mutex>> &)': function was implicitly deleted because a base class invokes a deleted or inaccessible function 'std::_Deleted_move_assign<_Base,_Ty> &std::_Deleted_move_assign<_Base,_Ty>::operator =(const std::_Deleted_move_assign<_Base,_Ty> &)'
对比之下,std::string相关的赋值操作却能正常运行:
std::string s; std::optional<std::string> os; os = std::string(s);
以及:
std::string s; std::optional<std::string> os; os = std::optional<std::string>(s);
原因分析
核心差异在于std::lock_guard和std::string的可拷贝/可移动特性:
std::lock_guard是专为独占管理互斥锁生命周期设计的工具,它的拷贝构造函数、移动构造函数、拷贝赋值运算符、移动赋值运算符都被显式删除——这意味着你无法复制或移动一个lock_guard对象,只能在原地构造它。std::string则完全支持拷贝和移动,所有相关的构造、赋值运算符都正常可用。
针对两段报错代码的具体解释:
- 代码(*):
std::optional的operator=没有接受std::lock_guard类型的重载。要直接将lock_guard赋值给optional,需要lock_guard能被移动或拷贝到optional的内部存储中,但lock_guard不支持这些操作,因此编译器找不到合适的赋值运算符。 - 代码(**):
std::optional<std::lock_guard<std::mutex>>的拷贝赋值运算符被编译器隐式删除——因为内部存储的lock_guard无法拷贝;同时,由于lock_guard没有移动构造函数,optional的移动赋值运算符也被删除,所以无法完成赋值操作。
而一开始能运行的代码,是直接在构造optional时原地构造了内部的lock_guard,这个过程不需要拷贝或移动,因此是合法的。
补充说明
你提到已经通过std::unique_ptr<std::lock_guard<std::mutex>>解决了问题,这种方式本质上是用指针间接管理lock_guard的生命周期,避免了直接拷贝/移动lock_guard的需求,确实是可行的替代方案。
内容的提问来源于stack exchange,提问作者H.v.M.
相关产品推荐
相关产品推荐

