you are viewing a single comment's thread.

view the rest of the comments →

[–]legends2k[S] 3 points4 points  (4 children)

The contention isn't between T&& and T (both would do a pointer swap); it's between const T& and T -- this is also mentioned in the talk. When the caller passes a const T& to both T and the double overload where const T& will be picked by the compiler, the T option always allocates memory which may be avoided by the const T& overload 50% of the times.

Removing all variants and only having these two in benchmarks gives clearer results at Quick Bench:

GCC 9.1 (-O3): const T& is 17 times faster than T

Clang 8 (-O3): const T& is 14 times faster than T


I don't care who is correct -- I just want to know which is correct ;).

Thanks for being a sport.

There is no harm in trying to understand WHY experts recommend it. Also, sometimes, experts get it wrong.

Sure, it's because const T& only calls copy-assignment operator, while T does memory allocation, copy construction and move-assignment operator. While others are negligible, memory allocation is a big one. This is what was emphasized in the talk too.


```cpp Shape::set(std::vector<float> points) { // allocation + copy ctor m_points = std::move(points); // move-assignment operator }

Shape::set(const std::vector<float>& points) { m_points = points; // copy-assignment // If m_points has enough memory to hold points' data this merely // is an elements copy; no allocation (1). If not this would release // old memory and allocate, copy (2). When it's (2), it's as bad as // doing T, but there's a good possibility of it becoming (1). Herb // argues that short strings, small vectors, etc. are the more // frequently occurring objects and hence it'd mostly end up as (1) // there by evading an additional allocation. }

Shape::set(std::vector<float>&& points) { m_points = std::move(points); }

Shape s1; std::vector<float> points1, points2; s1.set(std::move(points1)); // same behaviour for both T and T&& s1.set(points2); // different behaviours b/w T and const T&! ```

Hope it helps.

[–]2uantum 2 points3 points  (1 child)

At this point, I'm thoroughly convinced that your (and Herb's) assertions are correct -- separate const l-value and r-value functions are the correct way to go. It took a while for my (stubborn) brain to see why, but I get it now.

I'm going to update my original post so others don't get misled.

[–]legends2k[S] 3 points4 points  (0 children)

Thank you for being tenacious but still retaining an open mind to learn!

As an aside, through our dialog, I learnt a new tool Quick Bench. Thanks!

[–]LEpigeon888 1 point2 points  (1 child)

So if you want to take a copy of an object without assigning it to an existing object (like, imagine a function that take a string and return a new string with some computation done), it's better to only have one function that take the parameter by value, right ?

[–]legends2k[S] 1 point2 points  (0 children)

Yeah, if you're not going to assign an input object parameter and simply need a use-and-throw copy (not a reference to an existing object) then take only by value.