[英]why move constructor is not called
So I am new to move semantic and I am testing out the following code. 所以我是新手移动语义,我正在测试以下代码。 My understanding is that rvalue will invoke the move constructor and I expected A("123") will cause the move constructor to be called. 我的理解是rvalue将调用移动构造函数,我期望A(“123”)将导致移动构造函数被调用。 But when I ran this, the copy constructor is called instead. 但是当我运行它时,会调用复制构造函数。
#include <string>
#include <iostream>
#include <utility>
class A
{
std::string s;
public:
A(const std::string& in) : s(in) { std::cout << "ctor!\n";}
A(const A& o) : s(o.s) { std::cout << "move failed!\n"; }
A(A&& o) noexcept : s(std::move(o.s)) { }
};
class B
{
A d_a;
public:
B(const A& a) :d_a(a)
{}
};
int main()
{
std::cout << "Trying to move A\n";
B b(A("123")); // move-constructs from rvalue temporary
}
The issue is the constructor of B
: 问题是B
的构造函数:
B(const A& a) :d_a(a) {}
The function parameter const A&
is a const-qualified lvalue reference, which you can't cast to an rvalue. 函数参数const A&
是一个const限定的左值引用,您无法将其转换为右值。 You need to change the constructor to (or add a second one) 您需要将构造函数更改为(或添加第二个)
B(A&& a) : d_a(std::move(a)) {}
As a side note, you get the correct move semantics for the types in your example for free, if you just define them as 作为旁注,如果您只是将它们定义为,则可以免费获得示例中类型的正确移动语义
struct A {
std::string s;
};
struct B {
A d_a;
};
with the client code 使用客户端代码
B b{A{"123"}};
I understand that you wanted to not rely on compiler-generated special member functions for the sake of investigating the move-construction, I just didn't want to omit this shortcut, because this is the setup one should strive for: let the copy and move semantics of your class be automatically assembled by their data members. 我明白你不想依赖编译器生成的特殊成员函数来调查移动构造,我只是不想省略这个快捷方式,因为这是应该努力的设置:让复制和您的类的移动语义由其数据成员自动组装。
A const lvalue reference binds to anything. const lvalue引用绑定到任何东西。 Your B
has a constructor that takes A
by a const lvalue reference. 你的B
有一个构造函数,它通过const左值引用获取A
When you pass a temporary A
to this constructor, this will eventually lead to some parameter setting that looks like 当您将临时A
传递给此构造函数时,这最终会导致某些参数设置看起来像
const A& tmp = temporary_A;
and from then on, your A will be treated as a const lvalue reference which makes a call to copy constructor since that matches the signature. 从那以后,你的A将被视为一个const左值引用,它会调用复制构造函数,因为它与签名匹配。 You need to define a constructor in B
that takes A
by an rvalue reference. 您需要在B
中定义一个构造函数,它通过右值引用获取A
B(A&& a)
As things currently are, you will see a print out like: 就目前情况而言,您会看到如下打印输出:
Trying to move A 试图移动A.
ctor! 构造函数!
move failed! 搬家失败了!
ctor!
is printed when constructing the temporary and since your parameter is taken as const lvalue reference d_a(a)
calls the copy constructor. 在构造临时值时打印,因为您的参数被视为const左值引用d_a(a)
调用复制构造函数。 Below, modified code avoids copy. 下面,修改后的代码避免了复制。
#include <string>
#include <iostream>
#include <utility>
class A
{
std::string s;
public:
A(const std::string& in) : s(in) { std::cout << "ctor!\n";}
A(const A& o) : s(o.s) { std::cout << "move failed!\n"; }
A(A&& o) noexcept : s(std::move(o.s)) { }
};
class B
{
A d_a;
public:
B(A&& a) :d_a(std::move(a))
{}
};
int main()
{
std::cout << "Trying to move A\n";
B b(A("123")); // move-constructs from rvalue temporary
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.