0

私は移動セマンティクスを試していますが、右辺値参照が範囲外になるとどうなるか疑問に思っています。次のコードでは、左辺値を std::move すると実行時の問題が発生します

function(T t) with t = std::move(lvalue) --> SEGFAULT OR double free

しかし、入りません

function(T &&t) with t = std::move(lvalue) --> OK

理由を知っている人はいますか?

また、main() で 2 つのコード ブロックを入れ替えると、別のランタイム エラー 0_o が発生します。

// Compile with:
// g++ move_mini.cpp -std=c++11 -o move_mini
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <utility>
using namespace std;

int num_copied;

class T{
    public:
    T() : a(nullptr), b(nullptr){};

    T(const T &t) : a(new string(*t.a)), 
                    b(new string(*t.b)){
        num_copied++;
        };

    T(T &&t){
        *this = move(t);
        };

    T(string s1, string s2){
        this->a = new string(s1);
        this->b = new string(s2);
        };

    ~T(){
        delete this->a;
        delete this->b;
        };

    T& operator=(const T &lhs){
        num_copied++;
        delete this->a;
        delete this->b;
        this->a = new string(*lhs.a);
        this->b = new string(*lhs.b);
        return *this;
        };

    T& operator=(T &&lhs){
        swap(this->a, lhs.a);
        swap(this->b, lhs.b);
        return *this;
        };

    string *a;
    string *b;
    };

void modify1(T t){
    }

void modify3(T &&t){
    }

int main(){
    cout << "##### modify1(T t) #####" << endl;
    T t_mv1("e", "asdsa");
    num_copied = 0;
    modify1(move(t_mv1));
    cout << "t = move(t_mv)          copies " << num_copied << " times." << endl;
    cout << endl;

    cout << "##### modify3(T &&t) #####" << endl;
    T t_mv3("e", "aseeferf");
    num_copied = 0;
    modify3(move(t_mv3));
    cout << "t = move(t_mv)          copies " << num_copied << " times." << endl;
    cout << endl;

    return 0;
    }
4

1 に答える 1

5

ここから始めましょう:

modify1(move(t_mv1));

のパラメータを構築するためにmodify1、 のムーブ コンストラクタTが使用されます。

T(T &&t){
    *this = move(t);         // <--- this calls move assignment operator
};

上記のコメント行に注意してください。その時までに、object の 2 つのデータ メンバー*thisはデフォルトで初期化されます。これは、ポインターの場合、不確定な値が残ることを意味します。次に、移動代入演算子が呼び出されます。

T& operator=(T &&lhs){
    swap(this->a, lhs.a); // reads indeterminate values and invokes
    swap(this->b, lhs.b); // undefined behaviour
    return *this;
};

modify1戻ると、パラメーター オブジェクトが破棄され、デストラクタが初期化されていないポインターをT呼び出しdelete、未定義の動作が再び呼び出されます。

私は 2 番目の部分 (with modify3) を見ていませんが、似たようなことが起こっているのではないかと思います。

于 2013-09-15T20:15:23.407 に答える