简体   繁体   English

为什么在进行赋值时调用移动构造函数?

[英]Why is move constructor called when doing assignment?

I'm trying to make a sample implementation of std::unique_ptr.我正在尝试制作 std::unique_ptr 的示例实现。 Here is the code:这是代码:

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;
}

This code compiles and I'm able to see the value 4 in the output even after deleting the default assignment and copy constructor.此代码编译,即使在删除默认赋值和复制构造函数之后,我也能够在 output 中看到值 4。 What am I doing wrong?我究竟做错了什么?

In the assignment, move is called because the UniquePtr<int>(new int(4)) is constructing a temporary object, and in this case the compiler tries to use the move assignment if possible, else it would fall back to the copy assignment, which is deleted.在赋值中,调用 move 是因为UniquePtr<int>(new int(4))正在构造一个临时的 object,在这种情况下,编译器会尽可能使用移动赋值,否则它将回退到复制赋值, 被删除。

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.

As commented, the move assignment is not returning *this , you should enable all warnings.正如所评论的,移动分配没有返回*this ,您应该启用所有警告。 Also the last operator-> has a syntax error, it returns a pointer but expects a reference.最后一个operator->也有语法错误,它返回一个指针但需要一个引用。

Additionally, your code has a major issue, in case of exceptions you could have a memory leak.此外,您的代码有一个主要问题,如果出现异常,您可能会出现 memory 泄漏。 Suppose you write something like:假设您编写如下内容:

class Banana
{ ... }

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

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

If, for any reason, the computeAmount() function throws an exception, then the memory allocated by new could never be released, because computeAmount() could be executed between new and the constructor of the UniquePtr .如果由于任何原因, computeAmount() function 抛出异常,那么由new分配的 memory 永远不会被释放,因为computeAmount()可以在newUniquePtr的构造函数之间执行。 For this reason, we normally use std::make_unique() .出于这个原因,我们通常使用std::make_unique()

You should implement your own version of make_unique() and use it, it's trival, see here:https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique您应该实现自己的make_unique()版本并使用它,这很简单,请参见此处:https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique

Here more information about the issues and the solution: https://www.oreilly.com/library/view/effective-modern-c/9781491908419/ch04.html这里有关问题和解决方案的更多信息: https://www.oreilly.com/library/view/effective-modern-c/9781491908419/ch04.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM