在C++中移动构造函数和复制构造函数
move constructor and copy constructor in C++
我的理解是,当我们从函数返回本地对象时,如果存在移动构造函数,则会调用它。但是,我遇到了调用复制构造函数的情况,如函数foo2()
中的以下示例所示。为什么会这样?
#include <cstdio>
#include <memory>
#include <thread>
#include <chrono>
class tNode
{
public:
tNode(int b = 10)
{
a = b;
printf("a: %d, default constructor %s() is called at %s:%d n", a, __func__, __FILE__, __LINE__);
}
tNode(const tNode& node)
{
a = node.a;
printf("a: %d, copy constructor %s() is called at %s:%d n", a, __func__, __FILE__, __LINE__);
}
tNode& operator=(const tNode& node)
{
a = node.a;
printf("a: %d, copy assignment %s() is called at %s:%d n", a, __func__, __FILE__, __LINE__);
}
tNode(tNode&& node)
{
a = node.a;
printf("a: %d, move constructor %s() is called at %s:%d n", a, __func__, __FILE__, __LINE__);
}
tNode& operator=(tNode&& node)
{
a = node.a;
printf("a: %d, move assignment %s() is called at %s:%d n", a, __func__, __FILE__, __LINE__);
}
~tNode() { printf("a: %d, destructor %s() is called at %s:%d n", a, __func__, __FILE__, __LINE__); }
private:
int a = 0;
};
tNode foo()
{
tNode node;
return node;
}
tNode foo2()
{
std::unique_ptr<tNode> up = std::make_unique<tNode>(20);
return *up;
}
int main()
{
{
tNode n1 = foo();
tNode n2 = foo2();
}
// we pause here to watch how objects are created, copied/moved, and destroyed.
while (true)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
}
上面的代码是用g++ --std=c++17 -fno-elide-constructors
编译的 输出为:
a: 10, default constructor tNode() is called at testCopyControl.cpp:13
a: 10, move constructor tNode() is called at testCopyControl.cpp:31
a: 10, destructor ~tNode() is called at testCopyControl.cpp:40
a: 10, move constructor tNode() is called at testCopyControl.cpp:31
a: 10, destructor ~tNode() is called at testCopyControl.cpp:40
a: 20, default constructor tNode() is called at testCopyControl.cpp:13
a: 20, copy constructor tNode() is called at testCopyControl.cpp:19
a: 20, destructor ~tNode() is called at testCopyControl.cpp:40
a: 20, move constructor tNode() is called at testCopyControl.cpp:31
a: 20, destructor ~tNode() is called at testCopyControl.cpp:40
a: 20, destructor ~tNode() is called at testCopyControl.cpp:40
a: 10, destructor ~tNode() is called at testCopyControl.cpp:40
从输出中,我们知道当foo2()
返回*up
初始化临时tNode
对象时,会调用复制构造函数;为什么没有调用移动构造函数?
tNode foo()
{
tNode node;
return node;
}
和
tNode n1 = foo();
负责输出
a: 10, tNode() is called at testCopyControl.cpp:13
a: 10, move constructor tNode() is called at testCopyControl.cpp:31
a: 10, destructor ~tNode() is called at testCopyControl.cpp:40
a: 10, move constructor tNode() is called at testCopyControl.cpp:31
a: 10, destructor ~tNode() is called at testCopyControl.cpp:40
你看到的是被调用的默认构造函数,然后node
return 语句中开始将其视为右值以将其移动到返回值中,然后从返回值移动到n1
跟
tNode foo2()
{
std::unique_ptr<tNode> up = std::make_unique<tNode>(20);
return *up;
}
行为是不同的,因为您不返回函数本地对象。*up
为您提供了一个tNode&
,因此 return 语句不能将其视为右值。 由于它是一个左值,因此您必须调用复制构造函数才能将其复制到返回值中。 然后,与第一个示例一样,调用 move 构造函数将对象从返回值移动到n2
中。
下面的代码不会隐式移动构造的对象:
tNode foo2()
{
std::unique_ptr<tNode> up = std::make_unique<tNode>(20);
return *up;
}
这是因为,无论在我们看来多么明显/直观,编译器都无法证明从up
包含的对象中移动是安全的。它被迫通过复制返回。
您可以通过显式强制转换对象来强制它按 R 值返回:
tNode foo2()
{
std::unique_ptr<tNode> up = std::make_unique<tNode>(20);
return std::move(*up);
}
相关文章:
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 当从函数参数中的临时值调用复制构造函数时
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 使用复制构造函数复制双精度数组
- C 无可行的构造函数复制类型的变量
- 没有可行的构造函数复制类型 'MyString' 的数组元素
- 编译时,复制构造函数/复制分配和正常功能调用优化之间是否存在任何区别
- 如何最小化调用列表构造函数(复制构造函数)的次数?
- C 11矢量构造函数复制与范围
- 我定义了一个非复制构造函数;复制构造函数还会被隐式定义吗
- 可以将构造函数复制为转换运算符
- 将基类指针的构造函数复制到子类
- C++树类:构造函数/复制/内存泄漏
- 如何制作这个在模板构造函数复制中使用类型定义的类型的模板
- 将构造函数复制为模板化的成员函数
- 绕过私有复制构造函数/复制赋值C++
- C++通过构造函数复制对象
- 复制构造函数 - 复制C++中的对象
- 将带unique_ptr的类的构造函数复制到作为成员的抽象类