【问题标题】:why move constructor is not called为什么不调用移动构造函数
【发布时间】:2018-08-24 18:50:04
【问题描述】:

所以我是移动语义的新手,我正在测试以下代码。我的理解是右值将调用移动构造函数,我预计 A("123") 将导致调用移动构造函数。但是当我运行它时,会调用复制构造函数。

#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

}

【问题讨论】:

  • 请在此处提问时始终包含使您的代码可编译所需的头文件。
  • @πάνταῥεῖ 我不同意这个骗局并重新开放。 OP 的构造函数使用左值调用 A 的构造函数。

标签: c++


【解决方案1】:

问题是B的构造函数:

B(const A& a) :d_a(a) {}

函数参数const A&amp; 是一个 const 限定的左值引用,您不能将其强制转换为右值。您需要将构造函数更改为(或添加第二个)

B(A&& a) : d_a(std::move(a)) {}

附带说明,如果您将示例中的类型定义为,您可以免费获得正确的移动语义

struct  A {
    std::string s;
};

struct B {
     A d_a;
};

带有客户端代码

B b{A{"123"}};

我知道你不想依赖编译器生成的特殊成员函数来调查移动构造,我只是不想省略这个快捷方式,因为这是一个应该努力的设置:让类的复制和移动语义由它们的数据成员自动组装。

【讨论】:

  • 啊哈,我明白了。所以整个链也需要实现mctor
  • 这不是反过来吗?基本上,您将作为参数给出的右值引用转换为 const 左值引用,然后调用复制构造函数,不是吗?
  • 反之,右值引用需要转换为const左值引用
  • "左值引用,不能转换为右值 [reference]" -- 不正确,在某些情况下你可以这样做(虽然不是说这是个好主意)
【解决方案2】:

一个 const 左值引用绑定到任何东西。您的 B 有一个构造函数,它通过 const 左值引用获取 A。当你将一个临时的A 传递给这个构造函数时,这最终会导致一些参数设置看起来像

const A& tmp = temporary_A;

从那时起,您的 A 将被视为 const 左值引用,它会调用复制构造函数,因为它与签名匹配。您需要在B 中定义一个构造函数,该构造函数通过右值引用获取A

B(A&& a)

按照目前的情况,您将看到如下打印输出:

试图移动 A

导演!

移动失败!

ctor! 在构造临时对象时打印,因为您的参数被视为 const 左值引用 d_a(a) 调用复制构造函数。下面,修改后的代码避免了复制。

#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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 2014-01-24
    • 2023-03-16
    相关资源
    最近更新 更多