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

Compiler tries to use copy constructor even though I'm moving

本文关键字:移动 构造函数 复制 编译器      更新时间:2023-10-16

我正在尝试将东西从我的头安全装置中移入和移出:

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.
//...
}

我创建了这个类来插入到 Deque 中:

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时,编译器怎么可能复制东西?无法复制!

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

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

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

见 https://fr.slideshare.net/ripplelabs/howard-hinnant-accu2014 第30页

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

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

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

您不会获得移动构造函数和移动赋值运算符,因为您的复制构造函数和复制赋值运算符是用户删除/定义的(您删除了它们(。 您可以通过"=default"强制使用默认移动构造函数和移动赋值(就像删除一样(。

但是由于该类具有唯一的指针作为成员,该指针本身只能移动可构造且可移动可分配,因此您将免费删除复制构造函数和复制赋值。 只需删除删除语句,就会没事的,因为然后您再次获得移动操作。