Comment 2 for bug 1216521

Revision history for this message
Dominik (t-o-p-p-i) wrote :

This is expected behavior, according to... some people at some company.
There are however two paths to get going again.

A little background:
The tr1 headers were an experiment by the C++ standards committee, nothing more. They are not part of any standard. Apple is involved with the standards committee in an effort to make future committee experiments more obvious, and less likely to be mistaken for stable parts of a standard.

Additionally Apple is in the middle of transitioning from a gcc-based implementation of the std::lib (based on gcc-4.2) to a new-from-the-ground-up implementation that fully supports the new C++11 standard. This new implementation is also open source and the open source project can be found here: http://libcxx.llvm.org

Since 10.7/Lion, two implementations of the std::lib, the old gcc libstdc++, and this new llvm libc++ have been shipped.
With -lets say "newer"- OSes, the new libc++ is becoming the default used by the compiler clang.
This switch in the default std::lib is what's causing the symptom described in this ticket.

The older libstdc++ is still available and still has the same tr1 headers it always has.
The newer libc++ lacks the tr1 experiment. However most of tr1 was standardized with C++11, and now lives in namespace std, and in headers not prefixed with tr1/.

The C++ committee purposefully used the experimental std::tr1 namespace for the experiment so that they could (if need be) modify the tr1 components as they were standardized. And indeed this has happened. For the most part you will not notice any difference as you migrate from tr1 implementations to the C++11 std implementations. However there do exist a few corner cases. I would not worry about these corner cases. If you hit one, it will almost certainly come in the form of a compile-time error.

You are faced with two options:

1. Migrate your code from tr1 to std. I will show how to do this below. It is very easy. And it can be done in a manner in which your code is portable to both the old libstdc++ and the new libc++. This is the path "people at some company recommend".

2. Override the default std::lib choice and specifically choose the older gcc-4.2 based libstdc++. This is the easier path. But if this path is chosen, you are ultimately simply delaying the (relatively easy) work of doing step 1.

To override the default on the command line, add -stdlib=libstdc++ to both the compile and link command lines. You can also specifically choose the newer libc++ with -stdlib=libc++.

To do (1), the first step is to auto-detect which std::lib you are using. If you have already included any std header, you can do:

#ifdef _LIBCPP_VERSION

// using the new libc++

#else

// using the old libstdc++

#endif

If you have not yet included a std header, and need to include one gratuitously to find out whether or not it will define _LIBCPP_VERSION, do:

#include <ciso646> // detect std::lib

<ciso646> is a wonderful little C++ header that is specified to do absolutely nothing. So it is very cheap to include, and it will define _LIBCPP_VERSION if you are using the newer libc++, and otherwise won't.

Once you know which std::lib you are using, it becomes very easy to do things such as:

#ifdef _LIBCPP_VERSION
// using the new libc++

#include <memory>
typedef std::shared_ptr<MyType> MyTypePtr;

#else
// using the old libstdc++

#include <tr1/memory>
typedef std::tr1::shared_ptr<MyType> MyTypePtr;

#endif

Once done, it's easy to switch between libstdc++ and libc++ for testing purposes.