2016-04-26 10 views
2

非常に単純な、ベアボーンのC++クラスを作成して、スレッドセーフなリスト、つまりアクセス時に自動的にロックされるリストを実装しようとしています。残念ながら、コンパイラは、unique_lockを含む構造体を作成して返すことを許可したくありません。これは私が最初に試したものです:構造体にstd :: 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 locked() { 
      return LockedListAccess{ lock_t{mutex}, underlying_list }; 
     } 
}; 

これは、私は、これは構造体のためのブレース初期化子リスト/ C++ 11統一初期化は移動では動作しないことを意味推測している

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

で失敗します-only :: 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]’ 

私にエラーを与えてこのコンパイラエラーは、私がstd :: unique_lockの削除されたコピーコンストラクタを使用しようとしているものとしてlock(l), access(a)を含む行を指しているので、特に混乱します。私は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& 'になるとは思わないでしょう。そして既に 'rvalue 'であるものを' std :: move'する必要はありません。私に別のC++の奇妙なことを教えてくれてありがとう。 – Edward

+2

'lock_t&'にはなりません。これはまだtempオブジェクトにバインドされているr値参照ですが、l値として使用されます。これは当初私を混乱させましたが、l値が何であるかを知っていれば実際には理にかなっています。 I.E:命名されたものはたぶんl-valueであり、 'lock_t &&'は' l'という名前です。 –

関連する問題