且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

移动构造函数和移动重载赋值运算符的问题?

更新时间:2023-11-10 08:27:34

你的班级A有几个问题:

  • 您的赋值运算符不处理自赋值和泄漏:

  • Your assignment operator don't handle self assignment and leak:

A& A::operator=(const A& a)
{
    std::cout<<"overload operator=\n";
    if (this != &a)
    {
        p = a.p;
        delete[] s;
        s = new char[strlen(a.s) + 1];
        strcpy(s, a.s);
    }
    return *this;
}

  • 你的动作不是移动而是复制:

  • Your move doesn't move but copy:

    A::A(A&& a) : p(a.p), s(a.s)
    {
        a.s = nullptr;
        std::cout << "Move constructor\n";
    }
    
    A& A::operator=(A&& a)
    {
        std::cout << "Move overload operator=\n";
    
        if (this != &a) {
            p = a.p;
            delete [] s;
            s = a.s;
            a.s = nullptr;
        }
        return *this;
    }
    

    现在,关于

    A make_A()
    {
        A a(2,"bonapart"); // Constructor
        return a;
    }
    

    由于潜在的复制省略(NRVO),有几种情况(gcc 有标记为 -fno-elide-constructors 来控制)

    There are several scenario because of potential copy elision (NRVO) (gcc has flag as -fno-elide-constructors to control that)

    如果 NRVO 适用,则 a 是构造就地";所以不会发生额外的破坏/移动;

    if NRVO apply, then a is construct "in-place" so no extra destruction/move happens;

    否则有一个移动构造函数和a的销毁.

    else there is a move constructor and the destruction of a.

    A make_A()
    {
        A a(2,"bonapart"); // #2 ctor(int const char*)
        return a; // #3 move (elided with NRVO)
    } // #4 destruction of a, (elided with NRVO)
    
    int main()
    {
        A a1; // #1: default ctor
        a1 = // #5: Move assignment (done after make_A)
          make_A(); // #6: destructor of temporary create by make_A
    
        
        a1.display();
    } // #8: destructor of a1
    

    使用 NRVO

    default ctor
    ctor(int const char*)
    move assignment
    destructor
    display
    destructor
    

    没有 NRVO (-fno-elide-constructors)

    default ctor
    ctor(int const char*)
    move ctor
    destructor
    move assignment
    destructor
    display
    destructor
    

    演示

    为了

    A a1,a2;
    a2 = a1 = make_A();
    

    a1 = make_A(); 使用移动赋值.a2 = (a1 = make_A()) 使用复制赋值作为移动赋值返回(正确)A&

    a1 = make_A(); use move assignment. a2 = (a1 = make_A()) use copy assignment as move assignment returns (correctly) A&

    4在 Move 构造函数和 Move 重载 = 操作符中,我使用了 a.s=nullptr; 这个语句总是在 Move 语义中使用 fredoverflow(user) 解释了类似现在源不再拥有它的对象"之类的东西.但我不明白.因为如果我不写这个语句仍然没有问题一切正常.请解释这一点

    4 In Move constructor and Move overloaded = operator I used a.s=nullptr; This statement is always used in Move semantics fredoverflow(user) explained something like "now the source no longer owns the object it" but I am not getting it. Because if I did not write this statement still no problem everything works fine. please explain this point

    你的问题是你复制而不是移动.

    Your issue is that you do copy instead of move.

    如果你做 s = a.s; 而不是复制

    If you do s = a.s; instead of the copy

    s = new char[strlen(a.s) + 1];
    strcpy(s, a.s);
    

    那么 this->sas 都指向相同的数据,thisa> 会在它们的析构函数中释放(相同的)内存 ->双重免费错误.

    then both this->s and a.s would point of same data, and both this and a would free the (same) memory in their destructor -> double free error.

    a.s = nullptr; 可以解决这个问题.