[英]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()
可以在new
和UniquePtr
的构造函数之间执行。 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.