Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle evolving c++ std:: namespace? e.g.: std::tr1::shared_ptr vs. std::shared_ptr vs. boost::shared_ptr vs. boost::tr1::shared_ptr

For the code I am currently working on, we sometimes need to compile on some older systems with older compilers (e.g.- we run sims on an older IBM BlueGene/L, who's support contract dictates some quite old C++ compiler). The code itself makes use of shared_ptrs, and was originally written to use std::tr1::shared_ptr. When compiling on the old BlueGene machine, I quickly realized that it doesn't have a tr1:: implementation, and so I switched to boost::shared_ptr. Turns out there is also a boost::tr1::shared_ptr. Now that the code is being used more widely outside of our research group, portability is becoming even more important.

What is a (the?) best practice for handling these sorts of evolving standard library issues in a large-ish codebase? I am assuming that in the new C++11 standard, shared_ptr will no longer be in the tr1 namespace, which adds another potential: std::shared_ptr, however I am guessing widespread support for this will be a ways off. I'd like to be using the latest standard if possible, but need to maintain portability. Should I just stick with boost?

like image 974
MarkD Avatar asked Aug 17 '11 15:08

MarkD


3 Answers

To detect which namespace the shared_ptr is in, you need something like autoconf -- this is the reason why autoconf was created (detecting platform/compiler variations). You can do this with:

AC_LANG(C++)

AC_MSG_CHECKING([for std::shared_ptr])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
    [[#include <memory>]]
    [[std::shared_ptr<int> have_shared_ptr;]])
], [
    AC_MSG_RESULT([yes])
    AC_DEFINE_UNQUOTED([HAVE_STD_SHARED_PTR], 1, [Define to 1 if you have the `std::shared_ptr' class.])
], [
    AC_MSG_RESULT([no])
    AC_DEFINE_UNQUOTED([HAVE_STD_SHARED_PTR], 0, [Define to 1 if you have the `std::shared_ptr' class.])
])

Repeat for std::tr1::shared_ptr, boost::tr1::shared_ptr and boost::shared_ptr.

You can then create a shared_ptr.hpp file that is something like:

#include <config.h>

#if defined(HAVE_STD_SHARED_PTR)
    namespace ptr = std;
#elif defined(HAVE_STD_TR1_SHARED_PTR)
    namespace ptr = std::tr1;
#elif defined(HAVE_BOOST_SHARED_PTR)
    namespace ptr = boost;
#elif defined(HAVE_BOOST_TR1_SHARED_PTR)
    namespace ptr = boost::tr1;
#else
#   error No shared_ptr found.
#endif

... which you can then use as:

ptr::shared_ptr<int> pointer(new int(5));
like image 97
reece Avatar answered Nov 16 '22 09:11

reece


Partial answer to your question

boost::tr1 is invented exactly for the standard library implementations that don't have a tr1. To quote the documentation from here:

The TR1 library provides an implementation of the C++ Technical Report on Standard Library Extensions. This library does not itself implement the TR1 components, rather it's a thin wrapper that will include your standard library's TR1 implementation (if it has one), otherwise it will include the Boost Library equivalents, and import them into namespace std::tr1

like image 8
Armen Tsirunyan Avatar answered Nov 16 '22 11:11

Armen Tsirunyan


Why not have some special compile time checking? Kind of:

#if __GNUC__ > 3
     #define BOOST boost::
#else
     #define BOOST boost::tr1::
#endif

BOOST shared_ptr<...> ...

You can look up in the boost libraries, they have a lot of compiler/version-detection code.

See this question for details about the macros, especially this link: http://predef.sourceforge.net/.

like image 1
Vlad Avatar answered Nov 16 '22 09:11

Vlad