Using boost::shared_ptr with a view to replacing it later
Asked Answered
T

2

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.

Twotone answered 8/4, 2014 at 6:5 Comment(13)
Plain text substitution could be a viable option. It is unlikely that boost::shared_ptr -> std::shared_ptr will go wrong anywhere.Cobaltite
I don't want to go through the entire source code replacing boost with std later :(Twotone
You can write a three line script to do that.Cobaltite
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::_1Wheatear
@Wheatear sorry, i did not understand that. How does boost::_1 become std::placeholders::_1`?Twotone
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)Ilse
It don't answer question, but why using boost when you have std::tr1::shared_ptr ? Stay in STL ...Inconceivable
@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.Twotone
@berkus, is that a known fact for shared_ptr? I know it is in other cases, like result_of.Chiropodist
@Chiropodist 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)Ilse
@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?Chiropodist
It is either an alias for std::shared_ptr or boost's implementation under std::tr1::shared_ptr if unsupported by compiler.Ilse
@Twotone 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.Wheatear
C
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).

Chiropodist answered 8/4, 2014 at 6:10 Comment(1)
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.Twotone
P
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.

Posterior answered 8/4, 2014 at 7:9 Comment(6)
there is no such thing as "technically UB", only "UB" :-)Unlearn
@Unlearn Technically ;-), you're right. But there's a difference between "UB which will likely end badly (e.g. reading uninitialised values)" and "UB which will most likely be OK (e.g. adding a symbol to ::std which no part of the standard library references)."Posterior
well, technically speaking, a compiler could maintain a list of all Standard mandated identifiers in namespace std and abort compilation or unleash the nasal demons when it encounters your stuff.Unlearn
@Unlearn Of course. But no compiler I know does that. That's what I was referring to.Posterior
What is the meaning of "UB"?Chiropodist
@Chiropodist Sorry, it stands for "Undefined Behaviour." I've expanded it in the answer.Posterior

© 2022 - 2024 — McMap. All rights reserved.