7

Given two std::vector v1, v2.
I was wondering what are the benefits to use std::swap(v1, v2) over v1.swap(v2).

I have implemented a simple test code (I am not sure it is pertinent) regarding performance point of view :

#include <iostream>
#include <vector>
#include <random>
#include <chrono>
#include <algorithm>

#define N 100000

template<typename TimeT = std::chrono::microseconds>
struct Timer
{
    template<typename F, typename ...Args>
    static typename TimeT::rep exec(F func, Args&&... args)
    {
        auto start = std::chrono::steady_clock::now();
        func(std::forward<Args>(args)...);
        auto duration = std::chrono::duration_cast<TimeT>(std::chrono::steady_clock::now() - start);
        return duration.count();
    }
};

void test_std_swap(std::vector<double>& v1, std::vector<double>& v2)
{
    for (int i = 0; i < N; i ++)
    {
        std::swap(v1,v2);
        std::swap(v2,v1);
    }
}

void test_swap_vector(std::vector<double>& v1, std::vector<double>& v2)
{
    for (int i = 0; i < N; i ++)
    {
        v1.swap(v2);
        v2.swap(v1);
    }
}

int main()
{
    std::vector<double> A(1000);
    std::generate( A.begin(), A.end(), [&]() { return std::rand(); } );
    std::vector<double> B(1000);
    std::generate( B.begin(), B.end(), [&]() { return std::rand(); } );
    std::cout << Timer<>::exec<void(std::vector<double>& v1, std::vector<double>& v2)>(test_std_swap, A, B) << std::endl;
    std::cout << Timer<>::exec<void(std::vector<double>& v1, std::vector<double>& v2)>(test_swap_vector, A, B)  << std::endl;
    std::cout << Timer<>::exec<void(std::vector<double>& v1, std::vector<double>& v2)>(test_std_swap, A, B) << std::endl;
    std::cout << Timer<>::exec<void(std::vector<double>& v1, std::vector<double>& v2)>(test_swap_vector, A, B)  << std::endl;
}

According to outputs it seems that vector::swap seems faster without optimization -O0. Output is (in microseconds) :

20292
16246
16400
13898

And with -O3 there is no revelant difference.

752
752
752
760
coincoin
  • 4,595
  • 3
  • 23
  • 47

3 Answers3

11

Assuming a sane implementation, both of those functions should be implemented identically. So you should use whatever is most readable in your code.

In particular, if we look at the description for std::swap(vector<T> & x, vector<T> & y), it's effect is x.swap(y).

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
7

You should not use std::swap() directly in any case! Instead, you should use something like this:

using std::swap;
swap(x, y);

For std::vector<...> it probably doesn't make a difference as std::vector<...> obviously lives in namespace std. Otherwise the key difference is that with using std::swap() the default implementation is being used while with the approach outlined about ADL can find a better version.

Using swap(x, y) for std::vector<...>s x and y will just call x.swap(y). For consistency with other uses I would use the approach listed above.


References:

iammilind
  • 68,093
  • 33
  • 169
  • 336
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Thank you for the advice. Is this a reason why std::swap seems slower without optimization with the above example ? – coincoin Dec 29 '14 at 15:33
  • 4
    @coincoin: Profiling C++ code without optimizations is futile! For example, having function calls for everything trivially inlined adds a significant cost. Since production code surely always uses optimization the performance of unoptimized code is also irrelevant. – Dietmar Kühl Dec 29 '14 at 15:36
  • 1
    Downvoted because the actual answer to the question is only in the final paragraph, the rest is basically a comment on code style. Also I disagree with the first part, I would say only use "using" if you really have to, in this case it's not necessary. – RobinP Nov 06 '20 at 22:17
  • @DietmarKühl Your comment is simply not true, I do all my profiling on debug builds, I'm interested in optimising the algorithm being used, not removing a few function calls which make a trivial amount of difference. – RobinP Nov 06 '20 at 22:23
1

From implementation document:

void swap(vector& __x)

   *  This exchanges the elements between two vectors in constant time.
   *  (Three pointers, so it should be quite fast.)
   *  Note that the global std::swap() function is specialized such that
   *  std::swap(v1,v2) will feed to this function.

You can see that, std::swap(v1,v2) just invoke v1.swap(v2).

Jayhello
  • 5,931
  • 3
  • 49
  • 56