2016-04-26 68 views
2

我試圖創建一個非常簡單的基本C++類來實現線程安全列表,即當您訪問它時會自動鎖定的列表。不幸的是,編譯器不想讓我創建並返回一個包含unique_lock的結構。這是我最初試圖:不能將一個std :: unique_lock移動到一個struct

template<typename T> 
struct LockedQueue { 
    private: 
     std::mutex mutex; 
     using lock_t = std::unique_lock<std::mutex>; 
     std::list<T> underlying_list; 
    public: 
     struct LockedListAccess { 
      private: 
       lock_t lock; 
      public: 
       std::list<T> &access; 
     }; 
     LockedListAccess locked() { 
      return LockedListAccess{ lock_t{mutex}, underlying_list }; 
     } 
}; 

這種失敗

no matching function for call to ‘LockedQueue<tcp::socket>::LockedListAccess::LockedListAccess(<brace-enclosed initializer list>) 

我猜這意味着對於結構不動的工作,括號初始化列表/ C++ 11的統一初始化 - 只有std :: unique_lock類型。所以,我想創造我的結構明確的構造函數的unique_lock作爲右值引用,並將其移動到成員:

template<typename T> 
struct LockedQueue { 
    private: 
     std::mutex mutex; 
     using lock_t = std::unique_lock<std::mutex>; 
     std::list<T> underlying_list; 
    public: 
     struct LockedListAccess { 
      private: 
       lock_t lock; 
      public: 
       std::list<T> &access; 
       LockedListAccess(lock_t&& l, std::list<T>& a) : 
        lock(l), access(a) {}; 
     }; 
     LockedListAccess locked() { 
      return LockedListAccess{ std::move(lock_t{mutex}), underlying_list }; 
     } 
}; 

然而,這也失敗了,給我的錯誤

error: use of deleted function ‘std::unique_lock<_Mutex>::unique_lock(const std::unique_lock<_Mutex>&) [with _Mutex = std::mutex]’ 

這個編譯器錯誤尤其令人困惑,因爲它指向包含lock(l), access(a)的行,我試圖使用std :: unique_lock的已刪除副本構造函數。我宣稱llock_t&&,所以我怎麼可能調用複製構造函數?

我可以在互聯網上找到的大多數資源似乎表明,你可以用std :: move移動unique_locks,儘管似乎沒有人解決如何通過使用std ::構造一個包含unique_lock的對象的問題。移動。我在這裏做錯了什麼?

回答

5

問題:

LockedListAccess構造的上下文中,lock_t&& l實際上是一個L值。因此,您需要使用std::move將其重新轉換爲r值。一般經驗法則:總是std::move r值參考和始終std::forward轉發參考。

解決方案:

LockedListAccess(lock_t&& l, std::list<T>& a) 
    : lock(std::move(l)) 
    , access(a) 
{} 

而且你不需要移動臨時鎖定對象,因爲編譯器將一個臨時對象自動綁定到r值的參考。

此:

LockedListAccess locked() { 
    return LockedListAccess{ std::move(lock_t{mutex}), underlying_list } 
} 

可以成爲這樣的:

LockedListAccess locked() { 
    return LockedListAccess{ lock_t{mutex}, underlying_list } 
} 
+0

哇,這是一個奇怪的語言 「功能。」我永遠不會期望聲明'lock_t &&'的東西突然變成'lock_t&',只是因爲它在構造函數中。而且它看起來沒有必要對已經是右值的東西進行「std :: move」。感謝教我另一個C++的怪癖。 – Edward

+2

它不會成爲'lock_t&'。它仍然是一個綁定到臨時對象的r值引用,但它被用作l值。這一開始讓我感到困惑,但如果你知道什麼是l值,那麼它確實有意義。 I.E:任何被命名的東西都可能是一個l值,而你的'lock_t &&'有一個名字'l'; –

相關問題