1

I was doing some test with the move semantics after I found a way on stackoverflow to measure the elapsed time in a program and I'd like to ask something about it.

I have two classes A and B and B is derived from A:

class A
{
public:
    A()
    {
        for (int i = 0; i < MAX; i++)
            str[i] = "~~";

        for (int i = 0; i < MAX; i++)
            flt[i] = i;
    }

    std::string str[MAX];
    float flt[MAX];
};

B has two constructor defined like this:

B(const A*& a)
{
    for (int i = 0; i < MAX; i++)
        str[i] = a->str[i];

    for (int i = 0; i < MAX; i++)
        flt[i] = a->flt[i];
}



B(A*&& a)
{
    for (int i = 0; i < MAX; i++)
        str[i] = std::move(a->str[i]);

    for (int i = 0; i < MAX; i++)
        flt[i] = std::move(a->flt[i]);
}

where MAX = 1000

I noticed that the difference is not that big between the two constructors in terms of speed. And if I remove the std::move function from the second constructor the times I get are the same from the first ones. I'm expecting that the first constructor (with the const lvalue reference as argument) will copy each element of the two arrays into the two arrays of B, whereas the second constructor (with the rvalue reference as argument) will "move" the elements of the arrays.

The story doesn't change if I compare this

B(A&& a)
{
    for (int i = 0; i < MAX; i++)
        str[i] = std::move(a.str[i]);

    for (int i = 0; i < MAX; i++)
        flt[i] = std::move(a.flt[i]);
}

with this

B(A a)
{
    for (int i = 0; i < MAX; i++)
        str[i] = a.str[i];

    for (int i = 0; i < MAX; i++)
        flt[i] = a.flt[i];
}

I have no gain using the std::move function. Am I missing something about the move semantics?

Astinog
  • 1,151
  • 3
  • 12
  • 35
  • 1
    Where is your benchmark code? The compiler is probably smart enough to elide the copies/moves altogether. – fredoverflow Jan 22 '16 at 11:20
  • 4
    Moving a `float` is a copy. Moving a `std::string` might have roughly the same cost as a copy, if the string is small or if you are using pre-5 GCC's non-conforming COW string. – T.C. Jan 22 '16 at 11:24
  • I'm using this: http://stackoverflow.com/a/21995693/5214404 – Astinog Jan 22 '16 at 11:24

1 Answers1

3

As T.C said - moving a float is not going to make much difference.

Try your profiling with something like this:

class A
{
public:
    A()
        : strings(new std::string[MAX])
        , floats(new float[MAX])
    {
        for (int i = 0; i < MAX; i++)
            strings[i] = "~~";

        for (int i = 0; i < MAX; i++)
            floats[i] = i;
    }

    virtual ~A()
    {
        delete[] strings;
        delete[] floats;
    }

    std::string* strings;
    float* floats;
};

class B : public A
{
public:
    B(){}

    B(B&& other)
    {
        strings = other.strings;
        floats = other.floats;

        other.strings = nullptr;
        other.floats = nullptr;
    }
};

int main()
{
    B b;
    B bb(std::move(b));        
    return 0;
}

As you can see there are no loops in B's move constructor, we simply take other's internals and null it out to avoid any double deletion issues.

This is definitely NOT the best way to arrange the above code and should only be used as an example to illustrate move semantics.

Mohamad Elghawi
  • 2,071
  • 10
  • 14