【问题标题】:What happens if a rvalue reference goes out of scope?如果右值引用超出范围会发生什么?
【发布时间】:2013-09-15 19:51:08
【问题描述】:

我正在尝试移动语义,我想知道如果右值引用超出范围会发生什么。使用以下代码,如果我 std::move 一个左值到

中,我会遇到运行时问题
function(T t) with t = std::move(lvalue) --> SEGFAULT OR double free

但不进入

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

有人知道为什么吗?

另外,如果你在 main() 中交换两个代码块,你会得到一个不同的运行时错误 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;
    }

【问题讨论】:

  • 摆弄所有这些指针、动态分配和operator new的调用是一个非常糟糕的主意...
  • 移动构造函数中的 *this = move(t); 看起来真的可疑。
  • 你知道std::move实际上是做什么的吗?
  • @greatwolf 如果我省略 move() 也会出现同样的错误,但 t 应该是左值,我不想调用 op=(const T &t) 来避免复制
  • 您可以使用T(T &amp;&amp;t) : T() 来确保您的对象不是使用 uninit 指针构造的。

标签: c++ c++11 move-semantics rvalue-reference


【解决方案1】:

让我们从这里开始:

modify1(move(t_mv1));

构造modify1的参数,使用T的move构造函数:

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

注意上面的注释行。到那时,*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,再次调用未定义的行为

我没有看过第二部分(modify3),但我怀疑正在发生类似的事情。

【讨论】:

  • T(T &&t) : a(nullptr), b(nullptr){...} 修复了它。非常感谢:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-03
  • 1970-01-01
  • 2015-10-05
  • 1970-01-01
相关资源
最近更新 更多