Click here to Skip to main content
15,894,540 members
Articles / Programming Languages / C++11

Move Semantics and Perfect Forwarding in C++11

Rate me:
Please Sign up or sign in to vote.
4.93/5 (43 votes)
5 May 2015CPOL20 min read 103.7K   893   94  
Essential features in Visual C++ 11 and GCC 4.7.0: move, rvalue references, prvalues, xvalues, perfect forwarding.
//COPY ELISION

#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>


//#define MOVE_FUNCTIONALITY

int count_copies = 0;
int count_allocations = 0;
int elem_access = 0;

class Array
{
    int m_size;  
    double *m_array;    
public:
    Array():m_size(0),m_array(nullptr) {}
    Array(int n):m_size(n),m_array(new double[n])
    {
        std::cout << ">>>allocate:" << n << std::endl;
        count_allocations += n;        
    }

    Array(const Array& x):m_size(x.m_size),m_array(new double[m_size])
    {
        std::cout << ">>>(const Array& x) copy:" << m_size << std::endl;
        count_allocations += m_size;
        count_copies += m_size;        
        std::copy(x.m_array, x.m_array+x.m_size, m_array); 
    }

#ifdef MOVE_FUNCTIONALITY
    Array(Array&& x):m_size(x.m_size),m_array(x.m_array)
    {    
        std::cout << ">>>(Array&&) move" << std::endl;
        x.m_size = 0;       // clearing the contents of x
        x.m_array = nullptr;        
    }
#endif

    virtual ~Array()
    { 
        std::cout << ">>>delete: " << m_size << std::endl;
        delete [] m_array;
    }


    auto Swap(Array& y) -> void
    {        
        std::cout << ">>>swap" << std::endl;
        int n = m_size;
        double* v = m_array;
        m_size = y.m_size;
        m_array = y.m_array;
        y.m_size = n;
        y.m_array = v;
    }

#ifdef MOVE_FUNCTIONALITY
    auto operator=(Array&& x) -> Array&
    { 
        Swap(x);
        return *this;
    }
#endif

    auto operator=(const Array& x) -> Array&
    {                
        if (x.m_size == m_size)
        {
            std::cout << ">>>copy assignment:" << m_size << std::endl;
            count_copies += m_size;            
            std::copy(x.m_array, x.m_array+x.m_size, m_array);
        }
        else
        {
            Array y(x);
            Swap(y);
        }
        return *this;        
    }


    auto operator[](int i) -> double&
    {
        elem_access++;
        return m_array[i];
    }

    auto operator[](int i) const -> double
    {
        elem_access++;
        return m_array[i];
    }

    auto size() const ->int { return m_size;}

#ifdef MOVE_FUNCTIONALITY

    template<class T>
    friend auto operator+(T&& x, const Array& y) -> Array
    {      
        int n = x.m_size;        
        Array z(std::forward<T>(x));
        for (int i = 0; i < n; ++i)
        {
            elem_access+=2;
            z.m_array[i] += y.m_array[i];
        }        
        return z;
    }

    template<class T>
    friend auto operator+(T&& x, Array&& y) -> Array
    {        
        return std::move(y)+x;        
    }
#else
    friend auto operator+(const Array& x, const Array& y) -> Array
    {                
        int n = x.m_size;
        Array z(n);        
        for (int i = 0; i < n; ++i)
        { 
            elem_access += 3;
            z.m_array[i] = x.m_array[i] + y.m_array[i];
        }        
        return z;
    }          
#endif

    void print(const std::string& title) const
    {
        std::cout << title;
        for (int i = 0; i < m_size; ++i)
        {
            elem_access++;
            std::cout << " " << m_array[i];
        };     
        std::cout << std::endl;         
    }
};

const Array f()
{
    Array z(2);
    z[0] = 2.1;
    z[1] = 33.2;
    return z;
}

Array f1()
{
    Array z(2);
    z[0] = 2.1;
    z[1] = 33.2;
    return z;
}

void g(Array&& a)
{    
    a.print("g(Array&&)");
}

void g(const Array& a)
{    
    a.print("g(const Array&)");
}

void pf(Array a)
{    
    a.print("pf(Array)");
}

int main()
{
    {
        Array p(f());
        p.print("p");
        g(f());
        g(f1());
        pf(f());        
    }
    std::cout << "total allocations (elements):" << count_allocations << std::endl;
    int total_elem_access = count_copies*2 + elem_access;
    std::cout << "total elem access (elements):" << total_elem_access << std::endl;
    return 0;          
}


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions