Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost::shared_ptr and std::shared_ptr co-existence

We all know that both boost and c++11 has support for shared_ptr. Some compiler has support for c++11 while some doesn't. I would like to write my code so that when compiler support c++11 shared_ptr, it uses std::shared_ptr; when it doesn't, use boost::shared_ptr. What is the common/best practice for that?

Let me confine the discussion to GCC but not to particular version.

like image 268
Yan Zhu Avatar asked Jun 15 '13 19:06

Yan Zhu


People also ask

What is Boost :: shared_ptr?

shared_ptr is now part of the C++11 Standard, as std::shared_ptr . Starting with Boost release 1.53, shared_ptr can be used to hold a pointer to a dynamically allocated array. This is accomplished by using an array type ( T[] or T[N] ) as the template parameter.

Can shared_ptr be copied?

The ownership of an object can only be shared with another shared_ptr by copy constructing or copy assigning its value to another shared_ptr . Constructing a new shared_ptr using the raw underlying pointer owned by another shared_ptr leads to undefined behavior.

What happens when shared_ptr goes out of scope?

The smart pointer has an internal counter which is decreased each time that a std::shared_ptr , pointing to the same resource, goes out of scope – this technique is called reference counting. When the last shared pointer is destroyed, the counter goes to zero, and the memory is deallocated.

Is Boost shared_ptr thread safe?

The Thread Safety section of the Boost shared_ptr documentation says "shared_ptr objects offer the same level of thread safety as built-in types." The implementation must ensure that concurrent updates to separate shared_ptr instances are correct even when those instances share a reference count e.g.


1 Answers

C++0x / C++11 availability

The only way I am aware to detect whether GCC is using C++0x/C++11, as of today, is to check for the predefined macro __GXX_EXPERIMENTAL_CXX0X__:

#ifdef __GXX_EXPERIMENTAL_CXX0X__
    // C++11 code
#else
    // C++03 code
#endif

Note that this may change in the future (hence the EXPERIMENTAL part of the macro).

Edit: in fact there's a better way I didn't know of until @stephan pointed it out in a comment:

16.8/1 [cpp.predefined]

The following macro names shall be defined by the implementation:

__cplusplus

The name __cplusplus is defined to the value 201103L when compiling a C ++ translation unit.157

157) It is intended that future versions of this standard will replace the value of this macro with a greater value. Non-conforming compilers should use a value with at most five decimal digits.

So I guess you could do:

#if defined(__cplusplus) && (__cplusplus >= 201103L)

But I fear this wouldn't work with pre-standard C++0x GCC versions. So I'd probably use both __GXX_EXPERIMENTAL_CXX0X__ and __cplusplus together:

#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined(__cplusplus) && (__cplusplus >= 201103L))

C++0x / C++11 compatibility

However this may not always be enough to just detect whether C++0x/C++11 support is enabled: C++11 support has changed a lot throughout GCC versions, not only at the core language level but at the library level too.

My best bet would be to find which minimal GCC version you find acceptable for C++11 support and combine the above tests with a GCC version test, eg:

#if (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ >= 5)) // for GCC 4.7+

Switching between boost and std

Now, to switch between boost::shared_ptr and std::shared_ptr it's a bit cumbersome because C++03 doesn't support templated typedefs. I for one would wrap the required definitions in a template struct:

#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined(__cplusplus) && (__cplusplus >= 201103L))) \
        && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ >= 5))
    template<typename T>
    struct my_shared_ptr {
        typedef std::shared_ptr<T> type;
        // you may also want to forward make_shared etc, this is left as an exercise
    };
#else
    template<typename T>
    struct my_shared_ptr {
        typedef boost::shared_ptr<T> type;
        // you may also want to forward make_shared etc, this is left as an exercise
    };
#endif

my_shared_ptr<int>::type ptr(new int);

Edit: (again) whoops I just noticed @ComicSansMS's way of importing the right shared_ptr with a simple non-template using directive. Dunno why I didn't think about that.

Still, I stand with the way I described of detecting C++0x/C++11 on GCC.

like image 89
syam Avatar answered Sep 29 '22 23:09

syam