代码之家  ›  专栏  ›  技术社区  ›  RuLoViC

C++ 11中的语义迁移

  •  0
  • RuLoViC  · 技术社区  · 6 年前

    我想完全理解C++ 11中的移动语义。因此,我编写了几个类来查看何时调用不同的构造函数:

    #include <iostream>
    using namespace std;
    
    class A {
    public:
        A() : a1_(0) {std::cout << "Calling constructor" << std::endl;}
        A(A&& other) {
            std::cout << "Calling move constructor" << std::endl;
            a1_ = other.a1_;
            other.a1_ = 0;
        }
    
        // Move assignment operator.
        A& operator=(A&& other) {
            std::cout << "Calling move operator" << std::endl;
            if (this != &other) {
                a1_ = other.a1_;
                other.a1_ = 0;
            }
            return *this;
        }
    
        // Copy constructor.
        A(const A& other) {
            std::cout << "Calling copy constructor" << std::endl;
            a1_ = other.a1_;
        }
    
        // Copy assignment operator.
        A& operator=(const A& other) {
            std::cout << "Calling copy assignment operator" << std::endl;
            if (this != &other) {
                a1_ = other.a1_;
            }
            return *this;
        }
    
    private:
        int a1_;
    };
    
    class B {
        A oA_;
    
    public:
        B() {}
        void setoA(A a) {oA_ = a;}
            A getoA() {return oA_;}
    };
    
    A createA() {
        A a1;
        return a1;
    }
    
    B createB() {
        B tmpB;
        A tmpA;
        tmpB.setoA(tmpA);
        return tmpB;
    }
    
    int main() {
        B b;
        A a;
        b.setoA(a);
        std::cout << "**************************" << std::endl;
        b.setoA(createA());
        std::cout << "**************************" << std::endl;
        b.setoA(std::move(createA()));
        std::cout << "**************************" << std::endl;
        B b2;
        b2.setoA(b.getoA());
        std::cout << "**************************" << std::endl;
        createB();
    
        return 0;
    }
    

    当我检查此代码的输出时:

        Calling constructor
    
        Calling constructor
    
        Calling copy constructor
    
        Calling copy assignment operator
    
        ++++++++++++++++++++++++++++++++++
    
        Calling constructor
    
        Calling copy assignment operator
    
        ++++++++++++++++++++++++++++++++++
    
        Calling constructor
    
        Calling move constructor
    
        Calling copy assignment operator
    
        ++++++++++++++++++++++++++++++++++
    
        Calling constructor
    
        Calling copy constructor
    
        Calling copy assignment operator
    
        ++++++++++++++++++++++++++++++++++
    
        Calling constructor
    
        Calling constructor
    
        Calling copy constructor
    
        Calling copy assignment operator
    

    我有些怀疑:

    我想如果你通过 r-value ,将调用move构造函数,对吗?这不是吗 b.setoA(createA()); 一个 右值 ?

    如何调用move构造函数/运算符?

    2 回复  |  直到 6 年前
        1
  •  6
  •   Aconcagua    6 年前

    首先在第一节中,为什么要调用构造函数两次?

    因为你构造了 B 以及 A 前者有自己的例子 一个 ,第一个(意外的)构造函数调用来自。

    我想如果你传递r值,移动构造函数就会被调用,对吗?这不是吗 b.setoA(createA()); r值?

    构造函数是从内部调用的 createA (是的,返回值 但是,会发生复制省略,对象直接在的参数变量中实例化 setoA .

    刚毛 但是,与现在一样,选择了复制分配 a 是一个l值。如果你想搬家,你需要:

    void setoA(A a) { oA_ = std::move(a); }
    
        2
  •  0
  •   Brian Bi    6 年前

    编译器可以选择性地省略某些副本和移动。为了防止这种情况,使用 -fno-elide-constructors 在海合会和克朗。此外,在C++ 17中,某些移动的删除变得强制,因此强制编译器使用C++ 11移动语义,使用 -std=c++11 也。