我阅读了 Microsoft 教程(位于此处:https://learn.microsoft.com/en-us/cpp/cpp/move-constructors-and-move-assignment-operators-cpp?view=msvc-170)关于移动构造函数和移动赋值运算符,我不太明白何时调用移动构造函数。
下面是MemoryBlock类的代码
class MemoryBlock
{
public:
explicit MemoryBlock(size_t length)
: m_length(length),
m_data(new int[length])
{
std::cout << "In MemoryBlock(size_t). length = "
<< m_length << "." << std::endl;
}
virtual ~MemoryBlock()
{
std::cout << "In ~MemoryBlock(). length = "
<< m_length << ".";
if (m_data != nullptr)
{
delete[] m_data;
m_data = nullptr;
}
std::cout << std::endl;
}
// Copy ctor
MemoryBlock(const MemoryBlock& other)
: m_length(other.m_length),
m_data(new int[other.m_length])
{
std::cout << "In MemoryBlock(const MemoryBlock&). length = "
<< other.m_length << ". Copying resource." << std::endl;
std::copy(other.m_data, other.m_data + m_length, m_data);
}
// Copy assignment operator
MemoryBlock& operator=(const MemoryBlock& other)
{
std::cout << "In operator=(const MemoryBlock&). length = "
<< other.m_length << ". Copying resource." << std::endl;
if (this != &other)
{
delete[] m_data;
m_length = other.m_length;
m_data = new int[m_length];
std::copy(other.m_data, other.m_data + m_length, m_data);
}
return *this;
}
// Move ctor
MemoryBlock(MemoryBlock&& other) noexcept
: m_length(0),
m_data(nullptr)
{
std::cout << "In MemoryBlock(MemoryBlock&&). length = "
<< other.m_length << ". Moving resource." << std::endl;
m_data = other.m_data;
m_length = other.m_length;
other.m_data = nullptr;
other.m_length = 0;
}
// Move assignment
MemoryBlock& operator=(MemoryBlock&& other) noexcept
{
// Avoid assigning the object to itself
if (this != &other)
{
// Free the existing resource
delete[] m_data;
m_data = other.m_data;
m_length = other.m_length;
other.m_data = nullptr;
other.m_length = 0;
}
return *this;
}
private:
size_t m_length;
int *m_data;
};
我不明白的主要是。 理解为什么调用移动构造函数而不是复制构造函数
int main()
{
std::vector<MemoryBlock> v;
// In this way the copy ctor is called
MemoryBlock m(10);
v.push_back(m);
// And in this way the move ctor is called, why if std::move is not invoked?
v.push_back(MemoryBlock(25));
return 0;
}
编译构建代码并尝试理解,也在网上搜索资料无果
这是因为当你写
v.push_back(m);
时,表达式m
具有lvalue的值类别,所以使用了push_back( const T& )
的左值引用版本std::vector::push_back
,它使用了复制初始化。
另一方面,当您编写
v.push_back(MemoryBlock(25));
时,表达式 MemoryBlock(25)
是一个 rvalue,因此使用 push_back( T&& value )
的 std::vector::push_back
版本。所以这个版本使用移动构造函数。
void push_back( const T& value ); (1) void push_back( T&& value ); (2)
将给定的元素值附加到容器的末尾。
- 新元素被初始化为值的副本。
- value moved into 新元素。
MemoryBlock&&
是一个 rvalue reference。所以移动构造函数:
MemoryBlock(MemoryBlock&& other) noexcept
只要你传递一个右值就会被调用。有很多方法可以创建右值。
std::move
只是其中一种方式。其他人,就像你的情况,正在创建一个未命名的临时文件。这也可以通过一个函数来完成:
MemoryBlock foo() { ... }
...
MemoryBlock m{foo()};
所有这些都是右值,所以移动构造函数被调用。
总的来说:
rvalues
用于创建新对象时被调用lvalue
用于创建新对象时调用rvalues
lvalues
回答您的问题:我不明白的主要是。理解为什么调用移动构造函数而不是复制构造函数
在
v.push_back(m);
行中,m
是一个左值,因此调用了复制构造函数。在v.push_back(MemoryBlock(25));
行中,MemoryBlock(25)
是右值,因此调用了移动构造函数。
以下是关于此的有用阅读: