简体   繁体   English

为什么不调用移动构造函数

[英]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.

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