Voici un code minimal pour reproduire l'erreur.
> C:\Program Files (x86)\Microsoft Visual > Studio\2017\Community\VC\Tools\MSVC\14.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 > Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include\utility(405): > error C2440: '<function-style-cast>': cannot convert from 'initializer > list' to '_Mypair' C:\Program Files (x86)\Microsoft Visual > Studio\2017\Community\VC\Tools\MSVC\14.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 ]
Voici l'erreur.
Compilateur d'optimisation Microsoft (R) C / C ++ version 19.16.27026.1 pour x64 Copyright (C) Microsoft Corporation. Tous droits réservés.
#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)));
}
Erreur similaire pour le compilateur gcc .
Lorsque je supprime std :: mutex de la classe OU que je ne pousse pas l'objet sur std :: vector , alors il se compile correctement.
3 Réponses :
Selon la documentation sur std :: mutex a>.
std :: mutexn'est ni copiable ni ni déplaçable .
Puisque la classe A contient une std :: mutex variable mutex , elle n'est pas non plus déplaçable.
Le moyen de surmonter ce problème est d'utiliser des pointeurs (intelligents) vers std :: mutex.
Comme indiqué par PW et un indice fourni par freakish, je propose la solution ci-dessous.
#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>()));
}
J'ai modifié mon conteneur pour stocker le pointeur intelligent de l'objet au lieu de l'objet lui-même.
FWIW, vous devriez vraiment utiliser std :: unique_ptr sauf si vous avez vraiment besoin d'une propriété partagée. 90% du temps, non.
Comme P.W. fait remarquer, std :: mutex n'est ni copiable ni déplaçable, et pour une bonne raison. L'intérêt d'avoir un mutex est de se protéger contre l'accès multithread simultané à certaines données. L'opération de déplacement elle-même doit être protégée et le mutex doit être utilisé par l'opération de déplacement.
L'exemple suivant donne à la classe des données mobiles et montre comment le mutex doit être utilisé dans une opération de déplacement (les opérations de copie seraient similaires):
#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));
}