Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

[SOLVED] c++ 11, Moving slower than copying?!?



  • Hi all, some days ago I've started testing some of the c++11 features, in order to have a better understanding of the language. One of this test was benchmarking the execution of a piece of code that use std::move instead of copy, both by filling a vector without memory reserved, so vector must call move to move its elements, and the other to copy object; What i've see is that moving vectors is extremely efficient instead of copying it, instead for my class is a bit slower.. Searching on Internet one possibility is that the code is optimized by the compiler using copying elision, that is seems more efficient.. So my question is how i can benchmark better the code? There is something wrong with my move constructor? Why in my test moving is slower??

    @//System
    #include <iostream>
    #include <vector>
    #include <memory>
    #include <string>
    #include <QTime>

    //user

    using namespace std;
    class Constructors
    {
    public:
    //Cnstructors
    Constructors() : m_TestMember{0}{} // Empty Constructor
    Constructors(int value)
    {
    m_TestMember = value +5;
    m_TestMember1 = m_TestMember + 5;
    m_TestMember2 = m_TestMember1 + 5;
    m_TestMember3 = m_TestMember2 + 5;
    m_TestMember4 = m_TestMember3 + 5;
    } //Constructor
    ~Constructors()
    {
    // std::cout<<"destructing object..."<<std::endl;
    } //Destructor
    Constructors(const Constructors &c)
    {
    m_TestMember = c.m_TestMember;
    m_TestMember1 = c.m_TestMember1;
    m_TestMember2 = c.m_TestMember2;
    m_TestMember3 = c.m_TestMember3;
    m_TestMember4 = c.m_TestMember4;
    // std::cout<<"Copying constructor..."<<std::endl;
    } //Copy Constructor

    Constructors & operator=(Constructors &c)
    {
    m_TestMember = c.m_TestMember;
    m_TestMember1 = c.m_TestMember1;
    m_TestMember2 = c.m_TestMember2;
    m_TestMember3 = c.m_TestMember3;
    m_TestMember4 = c.m_TestMember4;
    std::cout<<"Copying constructor..."<<std::endl;
    }

    Constructors(Constructors &&c)
    {
    this->m_TestMember = c.m_TestMember;
    this->m_TestMember1 = c.m_TestMember1;
    this->m_TestMember2 = c.m_TestMember2;
    this->m_TestMember3 = c.m_TestMember3;
    this->m_TestMember4 = c.m_TestMember4;

    c.m_TestMember = 0;
    c.m_TestMember1 = 0;
    c.m_TestMember2 = 0;
    c.m_TestMember3 = 0;
    c.m_TestMember4 = 0;
    //    std::cout<<"Moving constructor..."<<std::endl;
    

    } //Move Constructor

    Constructors & operator=(Constructors &&c)
    {
    m_TestMember = std::move(c.m_TestMember);
    m_TestMember1 = std::move(c.m_TestMember1);
    m_TestMember2 = std::move(c.m_TestMember2);
    m_TestMember3 = std::move(c.m_TestMember3);
    m_TestMember4 = std::move(c.m_TestMember4);

    c.m_TestMember = 0;
    c.m_TestMember1 = 0;
    c.m_TestMember2 = 0;
    c.m_TestMember3 = 0;
    c.m_TestMember4 = 0;
    //    std::cout<<"Moving assignment..."<<std::endl;
    return *this;
    

    }

    private:
    int m_TestMember;
    int m_TestMember1;
    int m_TestMember2;
    int m_TestMember3;
    int m_TestMember4;
    };
    class ConstructorsB
    {
    public:
    //Cnstructors
    ConstructorsB() : m_TestMember{0}{} // Empty Constructor
    ConstructorsB(int value)
    {
    m_TestMember = value +5;
    m_TestMember1 = m_TestMember + 5;
    m_TestMember2 = m_TestMember1 + 5;
    m_TestMember3 = m_TestMember3 + 5;
    m_TestMember4 = m_TestMember3 + 5;
    } //Constructor
    ~ConstructorsB() {
    // std::cout<<"destructing object..."<<std::endl;
    } //Destructor
    ConstructorsB(const ConstructorsB &c)
    {
    m_TestMember = c.m_TestMember;
    m_TestMember1 = c.m_TestMember1;
    m_TestMember2 = c.m_TestMember2;
    m_TestMember3 = c.m_TestMember3;
    m_TestMember4 = c.m_TestMember4;
    // std::cout<<"Copying constructor..."<<std::endl;
    } //Copy Constructor

    private:
    int m_TestMember;
    int m_TestMember1;
    int m_TestMember2;
    int m_TestMember3;
    int m_TestMember4;
    };

    //! moving bendhmark, return number of millsec elapsed
    //! Note: Moving it's much more faster when assign object or initialize them
    //! instead of move in vector !
    float scopedMovingBenchmark(bool reserving, const int &elements)
    {
    QTime timer;

    vector<Constructors> constructorVector;
    vector<Constructors> constructorVector2;

    //! reserving half the time of execution..
    //! it avoid continuos moving, destructing
    if(reserving)
    constructorVector.reserve(elements);

    Constructors testClass{10};

    timer.start();

    for(int i{0}; i != elements; i++)
    constructorVector.push_back(testClass);
    // int a{std::move(10)};

    // constructorVector2 = std::move(constructorVector);
    return timer.elapsed()/1000.0f;
    }

    //! copying bendhmark, return number of millsec elapsed
    float scopedCopyingBenchmark(bool reserving, const int &elements)
    {
    QTime timer;

    vector<ConstructorsB> constructorVector;
    vector<ConstructorsB> constructorVector2{};

    //! reserving half the time of execution..
    //! it avoid continuos moving, destructing and copying
    if(reserving)
    constructorVector.reserve(elements);

    ConstructorsB testClass{10};

    timer.start();

    for(int i{0}; i != elements; i++)
    constructorVector.push_back(testClass);
    // int a = int {10};

    // constructorVector2 = constructorVector;
    return timer.elapsed()/1000.0f;
    }

    int main()
    {
    const int elements{1000000};
    const bool reserve{false};

    float movingMedia{0.0f};
    float copyingMedia{0.0f};
    
    for(int i{0}; i!=5; i++)
      movingMedia += scopedMovingBenchmark(reserve ,elements);
    for(int i{0}; i!=5; i++)
      copyingMedia += scopedCopyingBenchmark(reserve ,elements);
    
    movingMedia /= 5.0f;
    copyingMedia /= 5.0f;
    
    std::cout<<"moving time: "<<movingMedia<<endl;
    std::cout<<"copying time: "<<copyingMedia<<endl;
    std::cout<<"delta: "<<movingMedia - copyingMedia<<endl;
    

    return 0;
    }

    @



  • interresting, experiment with bigger iteration value:

    @int main( int argc, char **argv )
    {
    const int elements{1000000};
    const bool reserve{false};

    float movingMedia{0.0f};
    float copyingMedia{0.0f};
    

    double factor = 5;
    if ( argc > 1 )
    factor = atof( argv[1] );

    for(int i{0}; i < factor; i++)
      movingMedia += scopedMovingBenchmark(reserve ,elements);
    for(int i{0}; i < factor; i++)
      copyingMedia += scopedCopyingBenchmark(reserve ,elements);
    
    movingMedia /= factor;
    copyingMedia /= factor;
    

    ...
    @



  • I think i found the problem: basically moving is made for heap allocated memory, so when copying it avoid continuous memory allocation. So modifying the variable m_TestMember to a pointer type and consequently all the related moving copying constructor, the code is more faster.


Log in to reply