text: #include <exception>
  #include <memory>
  #include <mutex>
  #include <stack>
  #include <utility>
  
  struct EmptyStack : std::exception {
    const char* what() const noexcept { return "empty stack!"; }
  };
  
  template <typename T>
  class ConcurrentStack {
   public:
    ConcurrentStack() = default;
  
    ConcurrentStack(const ConcurrentStack& rhs) {
      std::lock_guard<std::mutex> l(rhs.m_);
      s_ = rhs.s_;
    }
  
    ConcurrentStack& operator=(const ConcurrentStack&) = delete;
  
    void push(T n) {
      std::lock_guard<std::mutex> l(m_);
      s_.push(std::move(n));
    }
  
    bool empty() const {
      std::lock_guard<std::mutex> l(m_);
      return s_.empty();
    }
  
    std::shared_ptr<T> pop() {
      std::lock_guard<std::mutex> l(m_);
      if (s_.empty()) {
        throw EmptyStack();
      }
      auto res = std::make_shared<T>(std::move(s_.top()));
      s_.pop();
      return res;
    }
  
    void pop(T& res) {
      std::lock_guard<std::mutex> l(m_);
      if (s_.empty()) {
        throw EmptyStack();
      }
      res = std::move(s_.top());
      s_.pop();
    }
  
   private:
    mutable std::mutex m_;
    std::stack<T> s_;
  };
  