2017-06-13 6 views
2

Voici mon problème.Tentative de référence d'une fonction supprimée, structure avec un membre mutex

J'ai une structure comme celle-ci.

struct threadInfo 
{ 
    std::condition_variable cv; 
    std::mutex m; 
    int priorityLevel; 
}; 

Lors de la construction de mon code, je reçois cette erreur

Erreur C2280 threadInfo::threadInfo(const threadInfo &): tentative de référencer une fonction supprimée PriorityListMutex

De ma compréhension, cela signifie que le constructeur de threadInfo est appelé et il essaie de copier le mutex ce qui n'est pas possible.

Je n'ai pas beaucoup d'expérience avec C++ et même si je comprends un peu ce qui se passe, je ne sais pas comment essayer de résoudre ce problème. Toute aide est la bienvenue!

Voici le code qui utilise ThreadInfo

threadInfo info; 
    info.priorityLevel = priority; 

    priorityListMutex.lock(); 
    for (std::list<threadInfo>::iterator it = threadList.begin(); it != threadList.end(); it++) 
    { 
     if ((*it).priorityLevel < info.priorityLevel) 
     { 
      threadList.insert(it, info); 
      break; 
     } 
     else if (it == threadList.end()) 
     { 
      threadList.push_back(info); 
      break; 
     } 
    } 
    priorityListMutex.unlock(); 
    std::unique_lock<std::mutex> lock(info.m); 
    info.cv.wait(lock); 

Je suppose que la structure est en cours de copie quelque part là-dedans, mais je suis tout à fait disparu où.

+0

S'il vous plaît poster un [MCVE] – Rama

+2

Ne copiez pas le struct? (Tous les deux 'condition_variable' et' mutex' ont leur copie ctor marquée comme suppression) – Borgleader

+0

Exemple de code ajouté de l'endroit où la structure est utilisée. – lhbortho

Répondre

1

Vous pouvez résoudre votre problème en évitant les copies et les struct directement: Montage dans la liste. Cela nécessite cependant un constructeur personnalisé. J'ai raccourci votre exemple de code pour afficher uniquement la partie: Montage:

#include <mutex> 
#include <condition_variable> 
#include <list> 

struct threadInfo 
{ 
    explicit threadInfo(int prio) : priorityLevel(prio) {} 

    std::condition_variable cv; 
    std::mutex m; 
    int priorityLevel; 
}; 

int main() 
{ 
    std::list<threadInfo> threadList; 

    int priorityLevel = 0; 

    for (std::list<threadInfo>::iterator it = threadList.begin(); it != threadList.end(); it++) 
    { 
     if ((*it).priorityLevel < priorityLevel) 
     { 
      threadList.emplace(it, priorityLevel); 
      break; 
     } 
     else if (it == threadList.end()) 
     { 
      threadList.emplace_back(priorityLevel); 
      break; 
     } 
    } 

    return 0; 
} 
+0

Vous pouvez utiliser 'emplace' avec' std :: move'. 'threadInfo' aura un constructeur de mouvement implicite défini par le compilateur. Vous pouvez faire 'threadList.emplace (it, std :: move (info));' et ne pas nécessiter de constructeur dédié. –

+0

Oui, ça marche. Réponse la plus simple et très facile à intégrer pour d'autres problèmes similaires aussi. Merci de montrer que ça existait! – lhbortho

+0

@ FrançoisAndrieux Je suppose que c'est juste une préférence personnelle à ce moment-là? Pour quelle raison l'un serait-il meilleur que l'autre? – lhbortho

0

Dans la bibliothèque C++ standard, les classes liées au thread, comme le mutex, ne possèdent pas de constructeur de copie.

Lorsqu'une affectation implique deux objets, comme

Class b(10); 
Class a = b; 

À la deuxième ligne, nous essayons de créer un objet d'initialisation d'un autre objet. Cela fait que le compilateur cherche un constructeur de copie, un constructeur développé spécifiquement à cet effet.

Comme avoir deux copies identiques d'un mutex n'est pas bon, la bibliothèque n'utilise pas cette méthode pour les classes liées au thread.

Habituellement, les compilateurs créent des constructeurs de copie par défaut au cas où ils seraient nécessaires, mais quand une classe d'une propriété de ce type ne peut pas le faire, elle vous donne ainsi une erreur.

Pour résoudre, vous devrez définir explicitement un constructeur de copie et gérer manuellement. Attention, vous devez garder à l'esprit que les choses liées aux threads comme mutex et cv ne devraient pas exister dans plus d'une copie.

+0

La deuxième ligne copie un int ... – Borgleader

+0

Ce sont les appels 'threadList.insert' et' threadList.push_back' qui tentent de copier les instances de 'threadInfo'. – IInspectable

+0

Cette réponse semble incomplète. Il y a aussi la solution de ne pas faire de copies en utilisant les fonctions de type 'emplace' avec' std :: move' au lieu de 'push_back' et' insert'. –

0

Le constructeur de copie de mutex est supprimé explicitement. Vous ne pouvez pas copier un mutex, cependant, si ce que vous faites est de déplacer plutôt que de copier (par exemple, vous n'aurez pas besoin de l'ancienne valeur de votre objet threadInfo) que vous pouvez déplacer le mutex en utilisant std::move et en écrivant un constructeur de déplacement pour votre objet threadInfo.

Cependant, un constructeur de mouvement peut causer des bogues difficiles à repérer, donc je ne le recommanderais pas. Une manière plus directe serait d'envelopper votre objet "info" dans un pointeur et de l'utiliser. Vous pouvez y parvenir en tant que tel:

auto info = std::make_shared<threadInfo>{}; 
info->priorityLevel = priority; 

priorityListMutex.lock(); 
for (std::list<std::shared_ptr<threadInfo>>::iterator it = threadList.begin(); it != threadList.end(); it++) 
{ 
    if ((*it).priorityLevel < info->priorityLevel) 
    { 
     threadList.insert(it, info); 
     break; 
    } 
    else if (it == threadList.end()) 
    { 
     threadList.push_back(info); 
     break; 
    } 
} 
priorityListMutex.unlock(); 
std::unique_lock<std::mutex> lock(info.m); 
info->cv.wait(lock); 

Prenez note toutefois que, dans ce cas, je suis sur un shared_ptr, qui est la façon de le faire « plus facile », car il ne casserez rien, mais probablement pas envie vous voulez faire, ce que vous voudrez probablement faire, c'est donner à l'objet 'threadList' la propriété de votre objet info.dans ce cas, vous déclarer comme unique_ptr:

auto info = std::make_uniq<threadInfo>{}; 

and move it into the threadList: 

threadList.insert(it, std::move(info));