std::mutex 作为 class 成员,并将 class 对象存储到容器
std::mutex as class member, and store class obect to container
下面是重现错误的最少代码。
#include <iostream>
#include <mutex>
#include <vector>
class A {
std::mutex mutex;
public:
A(){};
};
int main()
{
std::vector<std::pair<std::string,A>> aa;
A a;
//aa.push_back(std::make_pair(std::string("aa"),A()));
//aa.push_back(std::make_pair(std::string("aa"),a));
aa.push_back(std::make_pair(std::string("aa"),std::move(a)));
}
以下是错误。
Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27026.1 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
> C:\Program Files (x86)\Microsoft Visual
> Studio17\Community\VC\Tools\MSVC.16.27023\include\xlocale(319):
> warning C4530: C++ exception handler used, but unwind semantics are
> not enabled. Specify /EHsc C:\Program Files (x86)\Microsoft Visual
> Studio17\Community\VC\Tools\MSVC.16.27023\include\utility(405):
> error C2440: '<function-style-cast>': cannot convert from 'initializer
> list' to '_Mypair' C:\Program Files (x86)\Microsoft Visual
> Studio17\Community\VC\Tools\MSVC.16.27023\include\utility(405):
> note: No constructor could take the source type, or constructor
> overload resolution was ambiguous
> ..\examples\json_object\json.cpp(16): note: see reference to function
> template instantiation 'std::pair<std::string,A>
> std::make_pair<std::string,A>(_Ty1 &&,_Ty2 &&)' being compiled with
> [
> _Ty1=std::string,
> _Ty2=A ]
gcc
编译器出现类似错误。
当我从 class 中删除 std::mutex
或不将对象推到 std::vector
上时,它可以正常编译。
根据 std::mutex
上的文档。
std::mutex
is neither copyable nor movable.
由于classA
包含一个std::mutex
变量mutex
,所以也不可移动
正如 P.W 所指出的和 freakish 提供的提示,我想出了以下解决方案。
#include <iostream>
#include <mutex>
#include <vector>
#include <memory>
class A {
std::mutex mutex;
public:
A(){};
};
int main()
{
std::vector<std::pair<std::string,std::shared_ptr<A>>> aa;
A a;
//aa.push_back(std::make_pair(std::string("aa"),A()));
//aa.push_back(std::make_pair(std::string("aa"),a));
aa.push_back(std::make_pair(std::string("aa"),std::make_shared<A>()));
}
我修改了容器以存储对象的智能指针而不是对象本身。
作为P.W。指出,std::mutex
既不可复制也不可移动,这是有充分理由的。拥有互斥锁的全部意义在于防止对某些数据同时进行多线程访问。 move操作本身需要保护,mutex应该被move操作使用
以下示例为 class 提供了一些可移动数据,并展示了如何在移动操作中使用互斥锁(复制操作类似):
#include <iostream>
#include <mutex>
#include <vector>
#include <memory>
class A {
public:
A() {};
// Move constructor
A(A&& other) {
std::lock_guard<std::mutex> guard(other.m_mutex);
m_data = std::move(other.m_data);
}
// Move operator
A& operator=(A&& other) {
if (this == &other) return *this;
// Lock this and other in a consistent order to prevent deadlock
std::mutex* first;
std::mutex* second;
if (this < &other) {
first = &this->m_mutex;
second = &other.m_mutex;
} else {
first = &other.m_mutex;
second = &this->m_mutex;
}
std::lock_guard<std::mutex> guard1(*first);
std::lock_guard<std::mutex> guard2(*second);
// Now both this and other are safe to access. Do the actual data move.
m_data = std::move(other.m_data);
return *this;
}
private:
std::mutex m_mutex;
std::unique_ptr<int> m_data;
};
int main() {
std::vector<std::pair<std::string,A>> aa;
A a1;
A a2;
a1 = std::move(a2);
aa.emplace_back("aa", std::move(a1));
}
下面是重现错误的最少代码。
#include <iostream>
#include <mutex>
#include <vector>
class A {
std::mutex mutex;
public:
A(){};
};
int main()
{
std::vector<std::pair<std::string,A>> aa;
A a;
//aa.push_back(std::make_pair(std::string("aa"),A()));
//aa.push_back(std::make_pair(std::string("aa"),a));
aa.push_back(std::make_pair(std::string("aa"),std::move(a)));
}
以下是错误。
Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27026.1 for x64 Copyright (C) Microsoft Corporation. All rights reserved.
> C:\Program Files (x86)\Microsoft Visual
> Studio17\Community\VC\Tools\MSVC.16.27023\include\xlocale(319):
> warning C4530: C++ exception handler used, but unwind semantics are
> not enabled. Specify /EHsc C:\Program Files (x86)\Microsoft Visual
> Studio17\Community\VC\Tools\MSVC.16.27023\include\utility(405):
> error C2440: '<function-style-cast>': cannot convert from 'initializer
> list' to '_Mypair' C:\Program Files (x86)\Microsoft Visual
> Studio17\Community\VC\Tools\MSVC.16.27023\include\utility(405):
> note: No constructor could take the source type, or constructor
> overload resolution was ambiguous
> ..\examples\json_object\json.cpp(16): note: see reference to function
> template instantiation 'std::pair<std::string,A>
> std::make_pair<std::string,A>(_Ty1 &&,_Ty2 &&)' being compiled with
> [
> _Ty1=std::string,
> _Ty2=A ]
gcc
编译器出现类似错误。
当我从 class 中删除 std::mutex
或不将对象推到 std::vector
上时,它可以正常编译。
根据 std::mutex
上的文档。
std::mutex
is neither copyable nor movable.
由于classA
包含一个std::mutex
变量mutex
,所以也不可移动
正如 P.W 所指出的和 freakish 提供的提示,我想出了以下解决方案。
#include <iostream>
#include <mutex>
#include <vector>
#include <memory>
class A {
std::mutex mutex;
public:
A(){};
};
int main()
{
std::vector<std::pair<std::string,std::shared_ptr<A>>> aa;
A a;
//aa.push_back(std::make_pair(std::string("aa"),A()));
//aa.push_back(std::make_pair(std::string("aa"),a));
aa.push_back(std::make_pair(std::string("aa"),std::make_shared<A>()));
}
我修改了容器以存储对象的智能指针而不是对象本身。
作为P.W。指出,std::mutex
既不可复制也不可移动,这是有充分理由的。拥有互斥锁的全部意义在于防止对某些数据同时进行多线程访问。 move操作本身需要保护,mutex应该被move操作使用
以下示例为 class 提供了一些可移动数据,并展示了如何在移动操作中使用互斥锁(复制操作类似):
#include <iostream>
#include <mutex>
#include <vector>
#include <memory>
class A {
public:
A() {};
// Move constructor
A(A&& other) {
std::lock_guard<std::mutex> guard(other.m_mutex);
m_data = std::move(other.m_data);
}
// Move operator
A& operator=(A&& other) {
if (this == &other) return *this;
// Lock this and other in a consistent order to prevent deadlock
std::mutex* first;
std::mutex* second;
if (this < &other) {
first = &this->m_mutex;
second = &other.m_mutex;
} else {
first = &other.m_mutex;
second = &this->m_mutex;
}
std::lock_guard<std::mutex> guard1(*first);
std::lock_guard<std::mutex> guard2(*second);
// Now both this and other are safe to access. Do the actual data move.
m_data = std::move(other.m_data);
return *this;
}
private:
std::mutex m_mutex;
std::unique_ptr<int> m_data;
};
int main() {
std::vector<std::pair<std::string,A>> aa;
A a1;
A a2;
a1 = std::move(a2);
aa.emplace_back("aa", std::move(a1));
}