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);
}

我正在尝试查找构造函数的成本。

编译器是否足够聪明,可以将 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