2017-06-13 48 views
2

這是我的問題。試圖引用已刪除的函數,具有互斥成員的結構

我有這樣的結構。

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

當建立我的代碼,我得到這個錯誤

錯誤C2280 threadInfo::threadInfo(const threadInfo &):嘗試 引用刪除的功能PriorityListMutex

從我的理解這意味着threadInfo構造是所謂的,它試圖複製mutex這是不可能的。

我對C++沒有多少經驗,即使我有點理解發生了什麼,我不知道如何嘗試解決這個問題。任何幫助將是偉大的!

下面是一個使用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); 

我猜結構正在某處存在複製的代碼,但我完全缺少的地方。

+0

請發佈[MCVE] – Rama

+2

不要複製結構? ('condition_variable'和'mutex'都將它們的拷貝標記爲刪除) – Borgleader

+0

添加了正在使用結構的代碼示例。 – lhbortho

回答

1

您可以通過避免在列表中直接複製和放置結構來解決您的問題。這確實需要一個自定義的構造函數。我縮短了您的代碼示例以僅顯示部分版本:

#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

你可以使用'emplace'和'std :: move'。 'threadInfo'將有一個由編譯器定義的隱式移動構造函數。你可以做'threadList.emplace(it,std :: move(info));'並且不需要專門的構造函數。 –

+0

是的,工作。最簡單的答案,也很容易納入其他類似的問題。感謝您展示存在! – lhbortho

+0

@FrançoisAndrieux我想這只是個人喜好,在這一點上?任何理由都會比另一個更好? – lhbortho

0

在標準C++庫中,與線程相關的類(如互斥體)沒有複製構造函數。

當一個任務涉及兩個物體,如

Class b(10); 
Class a = b; 

在第二行中,我們試圖創建一個對象從另一個對象初始化。這使編譯器尋找一個拷貝構造函數,一個專門爲此目的而開發的構造函數。

由於有兩個相同的互斥體副本不好,所以該庫不會將這種方法用於與線程相關的類。

通常編譯器會在需要的時候創建默認的複製構造函數,但是當一個類是這種類型的屬性時它不能這樣做,所以它會給你和錯誤。

要解決,您將不得不顯式定義一個複製構造函數並手動處理。請注意,您應該記住與線程(如互斥體和cv)相關的內容不應存在於多個副本中。

+0

第二行復制int ... – Borgleader

+0

這是'threadList.insert'和'threadList.push_back'調用,它試圖複製'threadInfo'實例。 – IInspectable

+0

這個答案似乎不完整。還有一種解決方法是不使用'std :: move'替代'push_back'和'insert'使用'emplace'類型函數進行復制。 –

0

顯式刪除互斥體的複製構造函數。但是,如果您正在做的是移動而不是複製(例如,您不需要您的threadInfo對象的舊值),則無法複製互斥鎖,而只能使用std::move移動互斥鎖併爲您編寫移動構造函數threadInfo對象。

但是,移動構造函數可能會導致難以發現錯誤,所以我不會推薦這樣做。更直接的方法是將你的「信息」對象包裝在指針中並使用它。你可以做到這一點這樣:

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); 

確實注意到然而,在這種情況下我使用一個shared_ptr,這是「最簡單」的方式做到這一點,因爲它不會破壞任何東西,但可能不希望你想要做的,你最想做的事情是給你的info對象的'threadList'對象所有權。在這種情況下,您將聲明它爲unique_ptr:

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

and move it into the threadList: 

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