C++ 为什么在执行赋值时调用move构造函数?

C++ 为什么在执行赋值时调用move构造函数?,c++,C++,我正在尝试实现std::unique\u ptr的一个示例。代码如下: include <iostream> template<typename T> class UniquePtr { public: explicit UniquePtr(T * ptr) :m_ptr(ptr) {}; UniquePtr(UniquePtr const & other) = delete; UniquePtr& operator=(Uniq

我正在尝试实现std::unique\u ptr的一个示例。代码如下:

include <iostream>

template<typename T>
class UniquePtr
{
public:
  explicit UniquePtr(T * ptr)
    :m_ptr(ptr)
  {};

  UniquePtr(UniquePtr const & other) = delete;
  UniquePtr& operator=(UniquePtr const & other) = delete;

  explicit UniquePtr(UniquePtr && other)
  {
    m_ptr = other.m_ptr;
    other.m_ptr = nullptr;
  }

  UniquePtr & operator=(UniquePtr && other)
  {
    std::cout << "Move assignment called " << std::endl;
    m_ptr = other.m_ptr;
    other.m_ptr = nullptr;
  }

  ~UniquePtr()
  {
    delete m_ptr;
  }

  T& operator*()
  {
    return *m_ptr;
  }

  T& operator->()
  {
    return m_ptr;
  }

private:
  T * m_ptr = nullptr;
};

int main()
{
  UniquePtr<int> t(new int(3));
  t= UniquePtr<int>(new int(4));

  std::cout << *t << std::endl;
}

包括
模板
类唯一性
{
公众:
显式唯一性(T*ptr)
:m_ptr(ptr)
{};
UniquePtr(UniquePtr const&other)=删除;
UniquePtr&运算符=(UniquePtr const&其他)=删除;
显式UniquePtr(UniquePtr&其他)
{
m_ptr=其他m_ptr;
other.m_ptr=nullptr;
}
UniquePtr&运算符=(UniquePtr&其他)
{

std::cout在赋值中,调用move是因为
UniquePtr(new int(4))
正在构造一个临时对象,在这种情况下,如果可能的话,编译器会尝试使用move赋值,否则它将返回到复制赋值,该赋值将被删除

UniquePtr<int> t(new int(3));
t= UniquePtr<int>(new int(4)); // move assignment because temporary
auto k = t; // copy assignment since t is not temporary and so does not compile.
如果由于任何原因,
computeAmount()
函数抛出异常,那么由
new
分配的内存将永远无法释放,因为
computeAmount()
可以在
new
UniquePtr
的构造函数之间执行。因此,我们通常使用
std::make_unique()

您应该实现自己版本的
make_unique()
并使用它,它很繁琐,请参见此处:

以下是有关问题和解决方案的更多信息:

t=UniquePtr(新整数(4))
在本例中是一个
移动
。相关:你做错的不是从移动赋值操作符返回
*这个
。这是你唯一做错的事情。你能解释一下为什么你相信移动构造函数会被调用吗?@ChrisMM,我也是这么想的。但为什么会这样呢?你也会这样做吗第一个唯一的ptr?@SamVarshavchik指向的指针,因为该行被打印。我添加了
return*this
,但我仍然得到相同的结果。您应该澄清
auto k=t;
不会编译。它是一个临时对象,但对象仍然会泄漏,对吗?是否有任何方法可以避免?也许不是无论如何,这是一个真实的用例。如果出于任何原因,香蕉的构造函数抛出异常,那么new分配的内存将永远不会被释放。泄漏场景有点微妙,q.v.是的,在编写示例后,我意识到它不正确,很快就修复了。
class Banana
{ ... }

void eatBanana(UniquePtr<Banana> banana, int amountToEat);
int computeAmount();

eatBanana(UniquePtr<Banana>(new Banana(3)), computeAmount());