与移动构造函数混淆:无法调用移动构造函数
Confusion with move constructors: unable to call move constructor
我一直难以理解 C++ 中的移动构造函数。我用默认构造函数、复制构造函数、移动构造函数和析构函数制作了一个简单的 class。此外,我定义了一个具有两个重载的函数,一个接受对 class 的引用,一个接受对 class 的右值引用。我的测试代码如下。
#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
?
c s3(c());
不构造任何对象。它是一个函数声明。函数调用s3
,return类型为c
,参数类型为"pointer to function taking no parameters and returning c
"。所以你没有输出,因为函数声明不调用任何函数。
为了避免这种情况,您可以使用列表初始化,c s3{c()};
可能更符合您的想法。
您看不到第 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{}};
我一直难以理解 C++ 中的移动构造函数。我用默认构造函数、复制构造函数、移动构造函数和析构函数制作了一个简单的 class。此外,我定义了一个具有两个重载的函数,一个接受对 class 的引用,一个接受对 class 的右值引用。我的测试代码如下。
#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
?
c s3(c());
不构造任何对象。它是一个函数声明。函数调用s3
,return类型为c
,参数类型为"pointer to function taking no parameters and returning c
"。所以你没有输出,因为函数声明不调用任何函数。
为了避免这种情况,您可以使用列表初始化,c s3{c()};
可能更符合您的想法。
您看不到第 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{}};