What optimization does move semantics provide if we already have RVO?

前端 未结 8 1854
北海茫月
北海茫月 2020-12-04 17:50

As far as I understand one of the purposes of adding move semantics is to optimize code by calling special constructor for copying \"temporary\" objects. For example, in th

8条回答
  •  伪装坚强ぢ
    2020-12-04 18:52

    Imagine your stuff was a class with heap allocated memory like a string, and that it had the notion of capacity. Give it a operator+= that will grow the capacity geometrically. In C++03 this might look like:

    #include 
    #include 
    
    struct stuff
    {
        int size;
        int cap;
    
        stuff(int size_):size(size_)
        {
            cap = size;
            if (cap > 0)
                std::cout <<"allocating " << cap < 0)
                std::cout <<"allocating " << cap < 0)
                std::cout << "deallocating " << cap << '\n';
        }
    
        stuff& operator+=(const stuff& y)
        {
            if (cap < size+y.size)
            {
                if (cap > 0)
                    std::cout << "deallocating " << cap << '\n';
                cap = std::max(2*cap, size+y.size);
                std::cout <<"allocating " << cap <

    Also imagine you want to add more than just two stuff's at a time:

    int main()
    {
        stuff a(11),b(9),c(7),d(5);
        std::cout << "start addition\n\n";
        stuff e = a+b+c+d;
        std::cout << "\nend addition\n";
    }
    

    For me this prints out:

    allocating 11
    allocating 9
    allocating 7
    allocating 5
    start addition
    
    allocating 20
    allocating 27
    allocating 32
    deallocating 27
    deallocating 20
    
    end addition
    deallocating 32
    deallocating 5
    deallocating 7
    deallocating 9
    deallocating 11
    

    I count 3 allocations and 2 deallocations to compute:

    stuff e = a+b+c+d;
    

    Now add move semantics:

        stuff(stuff&& g):size(g.size), cap(g.cap)
        {
            g.cap = 0;
            g.size = 0;
        }
    

    ...

    stuff operator+(stuff&& lhs,const stuff& rhs)
    {
            return std::move(lhs += rhs);
    }
    

    Running again I get:

    allocating 11
    allocating 9
    allocating 7
    allocating 5
    start addition
    
    allocating 20
    deallocating 20
    allocating 40
    
    end addition
    deallocating 40
    deallocating 5
    deallocating 7
    deallocating 9
    deallocating 11
    

    I'm now down to 2 allocations and 1 deallocations. That translates to faster code.

提交回复
热议问题