-3

After testing this code:

#include <iostream>
#include <chrono>
#include <vector>
#include <string>


void x(std::vector<std::string>&& v){ }

void y(const std::vector<std::string>& v) { }

int main() {
    std::vector<std::string> v = {};

    auto tp = std::chrono::high_resolution_clock::now();

    for (int i = 0; i < 1000000000; ++i)
        x(std::move(v));

    auto t2 = std::chrono::high_resolution_clock::now();

    auto time = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - tp);

    std::cout << "1- It took: "  << time.count() << " seconds\n";

    tp = std::chrono::high_resolution_clock::now();

    for (int i = 0; i < 1000000000; ++i)
        y(v);

    t2 = std::chrono::high_resolution_clock::now();

    time = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - tp);

    std::cout << "2- It took: " << time.count() << " seconds\n";

    std::cin.get();
}

I get that using const-reference is actually ~15s faster than using move semantics, why is that? I thought that move semantics were faster, else, why would they add them? What did I get wrong about move semantics? thanks

Levon
  • 250
  • 2
  • 12
  • 2
    Your functions are empty, you're not testing anything but the parameter passing setup - that is if the calls aren't optimized out entirely. Maybe one gets optimized and the other doesn't? You should look at or post the generated code. – Mark Ransom Oct 13 '15 at 01:39
  • 3
    The fact that your `x` takes a `&&` indicates you don't understand move semantics. Consider reading [this question and answers](http://stackoverflow.com/questions/3106110/what-are-move-semantics). – user703016 Oct 13 '15 at 01:43
  • Moving is an optimization of _copy_ (for xvalues), not of passing by reference. Of course passing a simple reference is faster. – Emil Laine Oct 13 '15 at 01:52
  • Have you enabled optimization? – Constantin Baranov Oct 13 '15 at 02:12

1 Answers1

4

Your code makes no sense. Here is a simpler version of your code, substituted with int and cleaned up. Here is the assembly version of the code, compiled with -std=c++11 -02:

https://goo.gl/6MWLNp

There is NO difference between the assembly for the rvalue and lvalue functions. Whatever is the cause doesn't matter because the test itself doesn't make use of move semantics.

The reason is probably because the compiler optimizes both functions to the same assembly. You're not doing anything with either, so there's no point in doing anything different in the assembly than a simple ret.

Here is a better example, this time, swapping the first two items in the vector:

https://goo.gl/Sp6sk4

Ironically, you can see that the second function actually just calls the rvalue reference version automatically as a part of its execution.

Assuming that a function A which calls B is slower than just executing the function B, the speed of x() should outperform y().


std::move() itself has an additional cost. All things else being constant, calling std::move() is more costly than not calling std::move(). This is why the "move semantics" is slower in the code you gave us. In reality, the code is slower because you're not actually doing anything--both functions simply return as soon as they execute. You can also see that one version appears to call std::move() while the other doesn't.

Edit: The above doesn't appear to be true. std::move() is not usually a true function call; it is mainly a static_cast<T&&> that depends on some template stuff.

In the example I gave you, I'm actually making use of the move semantics. Most of the assembly is more important, but you can see that y() calls x() as a part of its execution. y() should therefore be slower than x().

tl;dr: You're not actually using move semantics because your functions don't need to do anything at all. Make the functions use copying/moving, and you'll see that even the assembly uses part of the "move semantics" code as a part of its copying code.

CinchBlue
  • 6,046
  • 1
  • 27
  • 58
  • 2
    Are you sure that there is a cost to calling move? I thought it's just a reinterpret cast; which has no runtime cost, and the function itself will be inlined so no overhead there. – Nir Friedman Oct 13 '15 at 02:43
  • Thanks for answering politely. I will take all this into account, the assembly code made it clear to me. Again, thanks. – Levon Oct 13 '15 at 21:30
  • @NirFriedman Yeah you're right; I changed the post to reflect this – CinchBlue Oct 13 '15 at 21:32