3

Based on pp. 8

Free Functions

template<typename T> void swap(scoped_ptr<T>& a,scoped_ptr<T>& b)

This function offers the preferred means by which to exchange the contents of two scoped pointers. It is preferable because swap(scoped1,scoped2) can be applied generically (in templated code) to many pointer types, including raw pointers and third-party smart pointers.[2] scoped1.swap(scoped2) only works on smart pointers, not on raw pointers, and only on those that define the operation.

int* pA = new int(10);
int *pB = new int(20);

boost::swap(pA, pB); // Error: could not deduce template argument for 'boost::scoped_ptr<T> &' from 'int *'

Question> How to swap raw pointers with boost::swap?

q0987
  • 34,938
  • 69
  • 242
  • 387

2 Answers2

5

This comes down to the swap idiom, or how swap should be implemented by user code. The recommended way of implementing swap for a type T in namespace N that has a set of members m1...mN is:

namespace N {
    void swap( T& lhs, T& rhs ) {
       using std::swap;
       swap( lhs.m1, rhs.m1 );
       ...
       swap( lhs.mN, rhs.mN );
    }
}

The idiom takes advantage of ADL (Argument Dependent Lookup). It first injects the definition of std::swap into scope, so that it is available when no better overload exists to swap a particular element. It then uses unqualified free function swap, knowing that if the type Tn of any of the mn members defines a free function swap, ADL will bring it into scope and the specialized swap will be used rather than std::swap.

What the documentation is saying is that you should not call ptr1.swap( ptr2 ), but rather unqualified swap( ptr1, ptr2 ) to swap any element including scoped_ptr objects, following the idiom above. That is, if you implement your swap as that, the swap function need not change because of a change in your member types, including whether a pointer is just a raw pointer or a scoped_ptr.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • non-templates always have precedence over templates during overload resolution, so a namespace-scoped non-template swap will take precedence over both boost::swap and std::swap. [Reference](http://stackoverflow.com/a/6115281/391104) – q0987 Mar 13 '12 at 19:14
  • argument-dependent lookup (ADL), or argument-dependent name lookup [ADL](http://en.wikipedia.org/wiki/Argument-dependent_name_lookup) – q0987 Mar 13 '12 at 19:19
  • Why not use `boost::swap` to swap the pointers? The entire point of its existence is to not have to do the using `std::swap` stuff. – GManNickG Mar 13 '12 at 19:56
  • @GManNickG: The quote actually provides a reason: *It is preferable because swap(scoped1,scoped2) can be applied generically* That is, the reason is not having to know that it is `scoped_ptr`, what namespace it was defined or whether it has an overloaded `swap` at all. If you are going to inject the knowledge of what is being swapped, the member function `scoped_ptr::swap` would suffice. – David Rodríguez - dribeas Mar 13 '12 at 20:11
  • @DavidRodríguez-dribeas: What do you mean? Using `boost::swap(x, y)` requires no knowledge on what type `x` and `y` are. What the quote is saying is that `swap(x, y)` is preferable to `x.swap(y);`, it's only lacking `boost::` qualification because it's a Boost book. My point still stands: why not use `boost::swap` for you swapping? It enables ADL automatically internally, precisely so you don't have to do the `using` stuff. – GManNickG Mar 13 '12 at 20:25
5

I don't understand why the other answers are telling you not to use boost::swap. The entire purpose of boost::swap is to hide the using std::swap; swap(x, y); business. This works just fine:

#include <boost/swap.hpp>

int main()
{
    int* pA = new int(10);
    int *pB = new int(20);

    boost::swap(pA, pB);

    delete pA;
    delete pB;
}

Obviously if you haven't included boost/swap.hpp this won't work. That's how you use boost::swap to swap two things. You should always prefer to swap two things in this form!

What you're reading is simply stating that boost::scoped_ptr also provides an overload of swap inside the boost namespace, so that this works too:

#include <boost/scoped_ptr.hpp>

int main()
{    
    boost::scoped_ptr<int> pA(new int(20));
    boost::scoped_ptr<int> pB(new int(20));

    boost::swap(pA, pB);
}

But it should be clear that this won't work:

#include <boost/scoped_ptr.hpp>

int main()
{
    int* pA = new int(10);
    int *pB = new int(20);

    boost::swap(pA, pB);

    delete pA;
    delete pB;
}

Because boost/scoped_ptr.hpp has not provided (and indeed doesn't have the responsibility to provide) a general implementation of boost::swap. If you want to use boost::swap in general, you must include boost/swap.hpp:

#include <boost/scoped_ptr.hpp>
#include <boost/swap.hpp>

int main()
{
    int* pA = new int(10);
    int *pB = new int(20);

    boost::scoped_ptr<int> pC(new int(20));
    boost::scoped_ptr<int> pD(new int(20));

    boost::swap(pA, pB);
    boost::swap(pC, pD);

    delete pA;
    delete pB;
}

Like that. If you have Boost available to do, do not fall back to the using std::swap stuff.

GManNickG
  • 494,350
  • 52
  • 494
  • 543