6

I am working on cross-platform code that needs shared pointers. For reasons beyond my control we cannot use C++11 just yet. So, I have suggested using boost::shared_ptr. When we do adopt C++11 (maybe a year down the line), we should be able to replace boost smart pointers with std smart pointers. My question is about the best way to use boost so that it is easier to switch later. Template aliasing is not available so the following is out:

namespace my {
    template <typename T>
    using shared_ptr = boost::shared_ptr<T>;
}

The other technique of wrapping the shared_ptr inside another struct results in ugly and unreadable APIs as I will then have to use it thus my::shared_ptr<int>::type:

 namespace my  {
     template<typename T>
     struct shared_ptr
     {
          typedef boost::shared_ptr<T> type;
     };
 }

I am looking for alternatives to this. Any suggestions will be appreciated.

EDIT: Another option I considered was this:

namespace my {
     using boost::shared_ptr;
}

And then use my::shared_ptr<int>. Later I would change boost to std in namespace my. However, I am not able to decide on the pro-s and con-s of each of the approaches to reach a decision.

341008
  • 9,862
  • 11
  • 52
  • 84
  • Plain text substitution could be a viable option. It is unlikely that `boost::shared_ptr` -> `std::shared_ptr` will go wrong anywhere. – juanchopanza Apr 08 '14 at 06:18
  • I don't want to go through the entire source code replacing `boost` with `std` later :( – 341008 Apr 08 '14 at 06:29
  • You can write a three line script to do that. – juanchopanza Apr 08 '14 at 06:30
  • Be aware that boost/std namespace isn't the only change. If you use placeholders, C++11 places them in the std::placeholders namespace, so boost::_1 becomes std::placeholders::_1 – kenba Apr 08 '14 at 06:41
  • @kenba sorry, i did not understand that. How does `boost::_1 become `std::placeholders::_1`? – 341008 Apr 08 '14 at 06:47
  • Actually, you can use boost::shared_ptr<> freely, it is mostly compatible with c++11 one, and boost usually provides "through" access to std:: version of the same class when it's available from the compiler (see boost::mutex/boost::thread which simply become std::mutex/std::thread when supported) – berkus Apr 08 '14 at 06:57
  • It don't answer question, but why using boost when you have std::tr1::shared_ptr ? Stay in STL ... – Mayhem50 Apr 08 '14 at 07:24
  • @BenREGNIER My code needs to be portable. I am using VS2012 on Windows which supports C++11 and XCode 4.6.3 (but w/o C++) on Mac. I am pretty sure tr1 is not portable. I would rather use `boost` on both platforms for now and then move to `std` on both platforms simultaneously later. Unless of course, I have got my facts wrong and I can safely use `std` on Windows and `tr1` on Mac without any problem. – 341008 Apr 08 '14 at 08:39
  • @berkus, is that a known fact for shared_ptr? I know it is in other cases, like result_of. – alfC Apr 08 '14 at 15:16
  • @alfC http://www.boost.org/doc/libs/1_55_0/doc/html/boost_tr1.html boost TR1 is supposed to do this (either use std equivalents, or boost's implementation in std::tr1) – berkus Apr 08 '14 at 16:17
  • @berkus, too technical for me. Does it mean that in the future (now?) `boost::shared_ptr` will be implemented in terms of `std::shared_ptr` or that `boost::shared_ptr` will be exactly the same type as `std::shared_ptr`? – alfC Apr 08 '14 at 19:01
  • 1
    It is either an alias for std::shared_ptr or boost's implementation under std::tr1::shared_ptr if unsupported by compiler. – berkus Apr 09 '14 at 15:19
  • @341008 sorry, my mistake, I'm so used to using shared pointers with boost::bind I forgot that placeholders are a bind thing. You don't need it, unless you're also converting from boost::bind to std::bind. – kenba Apr 10 '14 at 08:35

2 Answers2

5

Four options compatible with C++98,

1) use impl::shared_pointer<T>. And switch from:

namespace impl = boost; to namespace impl = std;

2) (more elegant but more risky) is to use shared_ptr without namespace qualification and later switch from

using boost::shared_ptr to using std::shared_ptr.

3) (ugly but I guess is the preferred industrial solution) Use macros all the way.

#if DETECTC++11
#define SHARED_PTR std::shared_ptr
#else
#define SHARED_PTR boost::shared_ptr
#endif

4) Combine the 3 above.

Anonymous namespaces can help to keep the using statements local to a file, so you have per-source-file control, e.g.:

namespace{
  using std::shared_ptr;
}

(I personally use 2. all the time).

alfC
  • 14,261
  • 4
  • 67
  • 118
  • Thanks for the suggestions. 2 is a little to risky for me. and I hate using macros for 3 is out. I like 1 and 4 - I have edited my question with a variant of the two. – 341008 Apr 08 '14 at 06:28
1

We do something like this in our project:

#if compiler_doesnt_support_c++11
  #include <boost/shared_ptr.hpp>

  namespace std {
    using boost::shared_ptr;
  }
#elif compiler_has_c++11_in_tr1
  #include <memory>
  namespace std {
    using std::tr1::shared_ptr;
  }
#else
  #include <memory>
#endif

And just use std::shared_ptr in the code.

Yes, it's technically Undefined Behaviour (as you're not allowed to add names to the ::std namespace like that), but it has worked without any problems for years.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455