【问题标题】:Confusion with move constructors: unable to call move constructor与移动构造函数混淆:无法调用移动构造函数
【发布时间】:2017-11-03 23:50:33
【问题描述】:

我一直难以理解 C++ 中的移动构造函数。我用默认构造函数、复制构造函数、移动构造函数和析构函数创建了一个简单的类。另外,我定义了一个具有两个重载的函数,一个接受对该类的引用,一个接受对该类的右值引用。我的测试代码如下。

#include <iostream>


class c {

public:

    c() {
        std::cout << "default constructor" << std::endl;
    }

    c(const c& s) {
        std::cout << "copy constructor" << std::endl;
    }

    c(c&& s) {
        std::cout << "move constructor" << std::endl;
    }

    ~c() {
        std::cout << "destructor" << std::endl;
    }

};

void f(c& s) {
    std::cout << "passed by reference" << std::endl;
}

void f(c&& s) {
    std::cout << "passed by rvalue reference" << std::endl;
}

int main() {

    c s1; // line 1
    std::cout << "\n";
    c s2(s1); // line 2
    std::cout << "\n";
    c s3(c()); // line 3

    std::cout << "\n";

    f(s1); // line 4
    std::cout << "\n";
    f(c()); // line 5

    getchar();
    return 0;

}

我得到的输出不是我所期望的。下面是我从这段代码中得到的输出。

default constructor

copy constructor

passed by reference

default constructor
passed by rvalue reference
destructor

我可以理解除line 3 之外的所有行的输出。在line 3 上,即c s3(c());c() 是一个右值,所以我希望s3 会被移动构造。但是输出并没有显示它是移动构造的。在line 5 上,我正在做同样的事情并将rvalue 传递给函数f(),它确实调用了接受rvalue 引用的重载。我很困惑,希望能提供任何有关这方面的信息。

编辑:如果我执行c s3(std::move(c()));,我可以调用移动构造函数,但我是否还没有将右值传递给 s3?为什么我需要std::move

【问题讨论】:

  • @NathanOliver 这不是这个的真正副本。这里发生的是最令人烦恼的解析,而不是复制省略。
  • @Angew 好电话。错过了。
  • @Angew 我实际上试图做的是通过其移动构造函数构造一个对象,当 NathanOliver 将我引导到另一个问题时,我真的认为这是重复的。在您指出之前,我什至没有注意到第 3 行的语句是函数签名。我也从未听说过最令人烦恼的解析,所以感谢您与我分享;我将阅读它以了解它是什么。

标签: c++ move-semantics rvalue-reference move-constructor most-vexing-parse


【解决方案1】:

第 3 行看不到任何输出的原因是它声明了一个函数,而不是变量。这是由于称为Most Vexing Parse 的歧义造成的。

比较 c s3(c())int foo(int ()),由于隐式类型调整,这与 int foo(int (*f)()) 相同。

要解决这个问题,请使用大括号初始化(实际上在 C++11 中引入了部分原因):

c s3(c{});

// or

c s3{c()};

// or

c s3{c{}};

【讨论】:

  • 感谢您提供的信息丰富的回答。这和下面MM的回答都回答了我的问题。但是,显然你比他们早了一分钟,所以我会接受你的回答。感谢您和 M.M 的时间和帮助。
【解决方案2】:

c s3(c()); 不构造任何对象。它是一个函数声明。该函数名为s3,返回类型为c,参数类型为“指向不带参数返回c的函数的指针”。所以你没有得到任何输出,因为函数声明不调用任何函数。

为了避免这种事情你可以使用列表初始化,c s3{c()}; 可能更符合你的想法。

【讨论】:

  • +1 for info '参数类型是“指向不带参数并返回 c 的函数的指针”'。如果是c(x),则参数类型为c,名称为x
猜你喜欢
  • 2015-02-14
  • 2011-05-22
  • 2020-03-22
  • 1970-01-01
  • 2015-02-21
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
  • 2016-03-28
相关资源
最近更新 更多