为什么我不能声明一个可选项std::lock_guard
,然后稍后再分配它?对于可选字符串,同样的事情也可以正常工作。
这有效:
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);
但事实并非如此:(**)
std::mutex m;
std::optional<std::lock_guard<std::mutex>> lg;
lg = std::optional<std::lock_guard<std::mutex>>(m);
但这确实:
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);
(*) 错误信息:
1>c:\dev\repos\tp_iu2\iu2\pretests\j00010_adaptercal.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:\dev\repos\tp_iu2\iu2\pretests\j00010_adaptercal.cpp(51): note: while trying to match the argument list '(std::optional<std::lock_guard<std::mutex>>, std::lock_guard<std::mutex>)'
(**) 错误信息:
1>c:\dev\repos\tp_iu2\iu2\pretests\j00010_adaptercal.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::unique_ptr<std::lock_guard<std::mutex>>
,所以我只是出于好奇才问。
std::optional<std::lock_guard<std::mutex>>
不可复制分配,因为std::lock_guard<std::mutex>
不可复制分配。这是设计使然。std::lock_guard
不可复制或分配。其唯一目的是提供一个 RAII 包装器,该包装器在构造时锁定互斥锁,并在离开范围时释放它。如果您不需要 RAII 包装器,那么std::lock_guard
就是错误的包装器。您可以绕过该问题,也可以使用可以默认构造而不需要的类型std::mutex
,稍后再分配以锁定互斥锁:您可以将字符串复制或移动到可选中,但互斥锁既不可复制也不可移动。所以我们不能使用赋值运算符。
我们可以使用
std::unique_lock
可移动的,或者我们可以将锁放入可选的:如果可以避免,我建议不要使用这种模式。如果可能的话,最好使用词法作用域(可能将语句分组到新块中)来开始和结束锁定保护。