C++ 编译器会自动为超出范围的局部变量使用 std::move 构造函数吗?
C++ does compiler automatically use std::move constructor for local variable that is going out of scope?
#include <iostream>
#include <string>
using namespace std;
class Class1 {
string s;
public:
Class1(const string& s_) : s(s_) {}
};
class Class2 {
string s;
public:
Class2(string s_) : s(std::move(s_)) {}
};
class Class3 {
string s;
public:
Class3(string s_) : s(s_) {}
};
int main()
{
string str = "ABC";
Class1 a(str);
Class2 b(str);
Class3 c(str);
}
我正在尝试查找构造函数的成本。
- Class 1: cost 1 copy constructor
- Class 2: 花费 1 个复制构造函数和 1 个移动构造函数
- Class 3: cost 1 copy constructor + {A.没什么,B. 移动构造函数,C. 复制构造函数}
编译器是否足够聪明,可以将 str
直接复制到 c.s
中?第三种情况的答案是什么?
大编辑:使用类向量class,答案是C。但是编译器有什么理由不能窃取s_
即使对象将在 s(s_)
之后被销毁 ?
#include <iostream>
#include <string>
using namespace std;
template <typename T = int>
class MyVector {
private:
int n;
T* data;
public:
MyVector() {
n = 0;
data = nullptr;
cout << "MyVector default constructor\n";
}
MyVector(int _n) {
n = _n;
data = new T[n];
cout << "MyVector param constructor\n";
}
MyVector(const MyVector& other) {
n = other.n;
data = new T[n];
for (int i=0; i<n; i++) data[i] = other.data[i];
cout << "MyVector copy constructor\n";
}
MyVector(MyVector&& other) {
n = other.n;
data = other.data;
other.n = 0;
other.data = nullptr;
cout << "MyVector move constructor\n";
}
MyVector& operator = (const MyVector& other) {
if (this != &other) {
n = other.n;
delete[] data;
data = new T[n];
for (int i=0; i<n; i++) data[i] = other.data[i];
}
cout << "MyVector copy assigment\n";
return *this;
}
MyVector& operator = (MyVector&& other) {
if (this != &other) {
n = other.n;
delete[] data;
data = other.data;
other.n = 0;
other.data = nullptr;
}
cout << "MyVector move assigment\n";
return *this;
}
~MyVector() {
delete[] data;
cout << "MyVector destructor: size = " << n << "\n";
}
int size() {
return n;
}
};
class Class1 {
MyVector<> s;
public:
Class1(const MyVector<>& s_) : s(s_) {}
};
class Class2 {
MyVector<> s;
public:
Class2(MyVector<> s_) : s(std::move(s_)) {}
};
class Class3 {
MyVector<> s;
public:
Class3(MyVector<> s_) : s(s_) {}
};
int main()
{
MyVector<> vec(5);
cout << "-----------\n";
cout << "Class1\n";
Class1 a(vec);
cout << "\n------------\n";
cout << "Class3\n";
Class2 b(vec);
cout << "\n------------\n";
cout << "Class3\n";
Class3 c(vec);
cout << "\n------------\n";
return 0;
}
s_
是初始化器 s(s_)
中的左值。所以会使用拷贝构造函数来构造s
。没有自动移动,例如在 return 语句中。不允许编译器省略此构造函数调用。
当然,只要可观察到的行为不变,编译器总是可以以任何它想要的方式优化程序。如果您不获取字符串对象的地址,您将无法观察到正在制作的字符串副本,因此编译器在任何情况下都可以自由地优化副本。
如果将构造函数参数存储在成员 by-value 中,则没有理由不使用 std::move
。
#include <iostream>
#include <string>
using namespace std;
class Class1 {
string s;
public:
Class1(const string& s_) : s(s_) {}
};
class Class2 {
string s;
public:
Class2(string s_) : s(std::move(s_)) {}
};
class Class3 {
string s;
public:
Class3(string s_) : s(s_) {}
};
int main()
{
string str = "ABC";
Class1 a(str);
Class2 b(str);
Class3 c(str);
}
我正在尝试查找构造函数的成本。
- Class 1: cost 1 copy constructor
- Class 2: 花费 1 个复制构造函数和 1 个移动构造函数
- Class 3: cost 1 copy constructor + {A.没什么,B. 移动构造函数,C. 复制构造函数}
编译器是否足够聪明,可以将 str
直接复制到 c.s
中?第三种情况的答案是什么?
大编辑:使用类向量class,答案是C。但是编译器有什么理由不能窃取s_
即使对象将在 s(s_)
之后被销毁 ?
#include <iostream>
#include <string>
using namespace std;
template <typename T = int>
class MyVector {
private:
int n;
T* data;
public:
MyVector() {
n = 0;
data = nullptr;
cout << "MyVector default constructor\n";
}
MyVector(int _n) {
n = _n;
data = new T[n];
cout << "MyVector param constructor\n";
}
MyVector(const MyVector& other) {
n = other.n;
data = new T[n];
for (int i=0; i<n; i++) data[i] = other.data[i];
cout << "MyVector copy constructor\n";
}
MyVector(MyVector&& other) {
n = other.n;
data = other.data;
other.n = 0;
other.data = nullptr;
cout << "MyVector move constructor\n";
}
MyVector& operator = (const MyVector& other) {
if (this != &other) {
n = other.n;
delete[] data;
data = new T[n];
for (int i=0; i<n; i++) data[i] = other.data[i];
}
cout << "MyVector copy assigment\n";
return *this;
}
MyVector& operator = (MyVector&& other) {
if (this != &other) {
n = other.n;
delete[] data;
data = other.data;
other.n = 0;
other.data = nullptr;
}
cout << "MyVector move assigment\n";
return *this;
}
~MyVector() {
delete[] data;
cout << "MyVector destructor: size = " << n << "\n";
}
int size() {
return n;
}
};
class Class1 {
MyVector<> s;
public:
Class1(const MyVector<>& s_) : s(s_) {}
};
class Class2 {
MyVector<> s;
public:
Class2(MyVector<> s_) : s(std::move(s_)) {}
};
class Class3 {
MyVector<> s;
public:
Class3(MyVector<> s_) : s(s_) {}
};
int main()
{
MyVector<> vec(5);
cout << "-----------\n";
cout << "Class1\n";
Class1 a(vec);
cout << "\n------------\n";
cout << "Class3\n";
Class2 b(vec);
cout << "\n------------\n";
cout << "Class3\n";
Class3 c(vec);
cout << "\n------------\n";
return 0;
}
s_
是初始化器 s(s_)
中的左值。所以会使用拷贝构造函数来构造s
。没有自动移动,例如在 return 语句中。不允许编译器省略此构造函数调用。
当然,只要可观察到的行为不变,编译器总是可以以任何它想要的方式优化程序。如果您不获取字符串对象的地址,您将无法观察到正在制作的字符串副本,因此编译器在任何情况下都可以自由地优化副本。
如果将构造函数参数存储在成员 by-value 中,则没有理由不使用 std::move
。