4

我一直有困难在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

+2

@NathanOliver这不是真的这一块的副本。这里发生的事情是最痛苦的解析,而不是复制elision。 – Angew

+0

@Angew好的电话。错过了。 – NathanOliver

+0

@Angew我实际上想要做的是通过它的移动构造函数构造一个对象,当NathanOliver指示我去处理另一个问题时,我真的认为这是重复的。我甚至没有注意到第3行的声明是一个函数签名,直到您指出。我从来没有听说过最棘手的解析,所以谢谢你与我分享;我会阅读它来了解它是什么。 – Deniz

回答

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{}}; 
+0

谢谢您提供的信息丰富的答案。这和M.M的答案都回答了我的问题。然而,显然你比他们早了一分钟,所以我会接受你的答案。感谢你和M.M为你的时间和帮助。 – Deniz

5

c s3(c());不构建任何对象。这是一个函数声明。该函数被称为s3,返回类型是c,参数类型是“函数指针不带参数并返回c”。所以你没有输出,因为函数声明不会调用任何函数。

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

+0

+1 for info'参数类型是“指向不带参数并返回c”的函数的指针。如果它是'c(x)',那么参数类型是'c'并且名称是'x' –