A simple thread-safe Deque in C++ I am trying to implement a thread-safe deque in C++.
ThreadSafeDeque will be used by a FileLogger class.
When threads call the log() function of FileLogger the messages will be push_back()ed to ThreadSafeDeque and return almost immediately. In a separate thread the FileLogger will pop_front() messages and write them to a file in its own pace.
Am I doing things correctly and efficient below?

#pragma once
#include &lt;deque&gt;
#include &lt;mutex&gt;
template&lt;class T&gt;
class ThreadSafeDeque {
public:
    void pop_front_waiting(T &amp;t) {
        // unique_lock can be unlocked, lock_guard can not
        std::unique_lock&lt;std::mutex&gt; lock{ mutex }; // locks
        while(deque.empty()) {
            condition.wait(lock); // unlocks, sleeps and relocks when woken up  
        }
        t = deque.front();
        deque.pop_front();
    } // unlocks as goes out of scope

    void push_back(const T &amp;t) {
        std::unique_lock&lt;std::mutex&gt; lock{ mutex }; 
        deque.push_back(t);
        lock.unlock();
        condition.notify_one(); // wakes up pop_front_waiting  
    }
private:
    std::deque&lt;T&gt;               deque;
    std::mutex                  mutex;
    std::condition_variable condition;
};
It's probably worth accepting a second template argument for an Allocator to be passed through to the std::deque:

template&lt;class T, class Allocator = std::allocator&lt;T&gt;&gt;
class ThreadSafeDeque {
    std::deque&lt;T, Allocator&gt; deque;
};


Technically, we do need to include &lt;condition_variable&gt;; we're not allowed to assume that &lt;mutex&gt; always pulls it in.

I don't like the interface to pop_front_waiting() - why does the caller have to pass an lvalue reference, instead of simply being returned the value?  Return-value optimisation will ensure there's no unnecessary copy.

The locking logic all looks good to me.  We can avoid the lock.unlock() by using a simple lock-guard with smaller scope:

void push_back(const T &amp;t)
{
    {
        std::lock_guard&lt;std::mutex&gt; lock{ mutex }; 
        deque.push_back(t);
    }
    condition.notify_one(); // wakes up pop_front_waiting  
}


From C++17, we can use constructor deduction and omit the template parameter from std::lock_guard and std::unique_lock, making the code a little easier to read.

It's helpful to show that members are intentionally default-constructed, and it pacifies g++ -Weffc++:

std::deque&lt;T&gt; deque = {};
std::mutex mutex = {};
std::condition_variable condition = {};