即使我在移动,编译器仍尝试使用复制构造函数

时间:2019-08-29 08:16:38

标签: c++

我正在尝试从我的thead安全双端队列中移入和移出

template <typename T>
class ThreadSafeDeque
{
//..
    T pop_front(void) noexcept
    {
        std::unique_lock<std::mutex> lock{_mutex};

        while (_collection.empty())
        {
            _condNewData.wait(lock);
        }
        auto elem = std::move(_collection.front());
        _collection.pop_front();
        return elem;
    }
private:
    std::deque<T> _collection;            // Concrete, not thread safe, storage.
    //...
}

我创建了要插入双端队列的此类:

class DecodedFrame
{
public:
    DecodedFrame(){}
    DecodedFrame(const DecodedFrame &decodedFrame) = delete;
    DecodedFrame &operator=(const DecodedFrame &) = delete;
    std::unique_ptr<AVFrame, AVFrameDeleter> avFrame;

现在我正在尝试

std::shared_ptr<ThreadSafeDeque<DecodedFrame>> decodedFramesFifo;
//add some `DecodedFrame`s to decodedFramesFifo
DecodedFrame decodedFrame = std::move(decodedFramesFifo->pop_front());

但是编译器抱怨我删除了复制分配构造函数,即使我试图使用移动分配构造函数也是如此。我的猜测是,发生这种情况是因为pop_front返回了T,而不是T&。但是,返回引用毫无意义,因为该对象应该永远离开双端队列,因此对它的引用将死亡。

我如何在这里搬东西?

ps :当DecodedFrame持有unique_ptr时,编译器如何复制内容?无法复制!

3 个答案:

答案 0 :(得分:4)

问题是您声明了复制控制器和赋值运算符。声明删除它们并不重要,它仍然是用户提供的声明。这抑制了移动操作的隐式声明。您的选择是

  1. 显式默认移动操作。
  2. 删除复制操作声明,由于不可复制成员,它们仍将隐式删除。

答案 1 :(得分:3)

copy-ctor / assign操作被删除(这些也是声明),但是不会隐式声明/定义move-ctor / assign操作。

参见https://fr.slideshare.net/ripplelabs/howard-hinnant-accu2014的p30

您必须声明(默认)它们。

DecodedFrame(DecodedFrame &&) = default;
DecodedFrame &operator=(DecodedFrame &&) = default;

为了避免这种令人沮丧的行为,您应该考虑五个规则
https://en.cppreference.com/w/cpp/language/rule_of_three#Rule_of_five

答案 2 :(得分:2)

您没有得到move构造函数和move赋值运算符,因为您的副本构造函数和copy赋值运算符是由用户指定/定义的(已删除)。您可以通过“ = default”强制使用默认的move构造函数并移动赋值(就像使用delete一样)。

但是,由于类具有作为成员的唯一指针,该指针本身只能进行构造和移动分配,因此您将免费删除复制构造函数和复制分配。只需删除delete语句就可以了,因为您随后又可以进行移动操作。