与移动构造函数混淆:无法调用移动构造函数

Den*_*niz 4 c++ rvalue-reference most-vexing-parse move-constructor move-semantics

我在使用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;

}
Run Code Online (Sandbox Code Playgroud)

我得到的输出并不是我所期待的.以下是我从此代码中获得的输出.

default constructor

copy constructor

passed by reference

default constructor
passed by rvalue reference
destructor
Run Code Online (Sandbox Code Playgroud)

我可以理解所有行的输出除外line 3.上line 3,这是c s3(c());,c()是一个右值,所以我会想到s3会被举动构成.但输出并未表明它是移动构造的.在line 5,我正在做同样的事情并传递rvalue给函数f(),它确实调用接受rvalue引用的重载.我很困惑,并希望了解有关此事的任何信息.

编辑:如果我这样做,我可以调用移动构造函数c s3(std::move(c()));但是我还没有将rvalue传递给s3吗?我为什么需要std::move

Rei*_*ica 9

您没有看到第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{}};
Run Code Online (Sandbox Code Playgroud)


M.M*_*M.M 5

c s3(c());不构造任何对象.这是一个功能声明.调用该函数s3,返回类型为c,并且参数类型为"指向不带参数且返回的函数的指针c".因此,您没有输出,因为函数声明不会调用任何函数.

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