C ++ std: .auto_ptr or std :: unique_ptr (to support multiple compilers, even older C ++ 03 compilers)?
I'm trying to update some C ++ code, I would like to move to more modern code (C ++ 11), but I still need to compile the code with some older compilers (C ++ 03 compatible), due to the supported platform limitations.
I know that std :: auto_ptr is deprecated in C ++ 11 compilers, but due to older compiler support, I cannot just replace them with std :: unique_ptr.
Is there a good practice to handle this "old compiler support, but start moving towards C ++ 11"?
As you noted, std :: auto_ptr <> is deprecated in C ++ 11 ( Reference ).
Moving to C ++ 11 std :: unique_ptr <> is the correct way to go, as also pointed out by Herb Sutter in GotW89 :
- What is an auto_ptr trade?
auto_ptr is most vividly described as a valiant attempt to create a unique_ptr before C ++ transfers semantics. auto_ptr is now deprecated and should not be used in new code.
If you have auto_ptr in your existing codebase when you get the chance to try a global lookup and replace auto_ptr with unique_ptr; the vast majority of uses will work the same, and it might be detected (like a compile-time error) or fix (quietly) an error or two that you didn't know you had.
Also note that C ++ 17 will remove std :: auto_ptr.
I think there might be different ways to solve your problem, the "correct" one also depends on how your actual code is written.
Several variants:
Option 1
Use boost :: unique_ptr
Option 2
Conditional use auto_ptr or unique_ptr based on __cplusplus.
class Myclass {
#if __cplusplus <201103L
std :: auto_ptr m_ptr;
#else
std :: unique_ptr m_ptr;
#endif
...
This will be scattered all over the places where you refer to auto_ptr, I don't like that.
It might seem less awkward if all your references to std :: auto_ptr have already been printed (just conditionally change the typedef).
Option 3
Conditional use usage and aliases to "define" auto_ptr (and refer to it without std :: namespace).
#if __cplusplus <201103L
using std :: auto_ptr;
#else
template
using auto_ptr = std :: unique_ptr;
#endif
Disadvantage: you keep using "auto_ptr", but in C ++ 11 this means std :: unique_ptr.
In fact they are confused ...
Option 3.1
Probably slightly better than option 2: the
other way around, using aliases and preferring the name unique_ptr.
Option 4
Wrap a std :: smart pointer (conditionally auto_ptr or unique_ptr) in your own smart pointer class.
This can be cumbersome and requires finding and replacing all auto_ptr references with your new class.
Other dirty options
Other options include definitions inside std :: namespace, which I think is prohibited by the standard,
or using the #define preprocessor for ... ehm ... "rename" unique_ptr to auto_ptr only for older C ++ 03 compilers.
source to share
If I was serious I would create a namespace notstd
.
The goal would be that in C ++ 11 it notstd
consists of a series of type aliases std
. In C ++ 03, it has pseudo C ++ 11 code.
C ++ 03 code notstd
will not be 100% compatible with C ++ 11 std
, but rather valid C ++ 03 notstd
will in turn lead to valid C ++ 11.
For example, I could use special tagged references like reference-wrapper for references notstd::move
instead of rvalue references, and my move-only types require such a tagged "reference wrapper".
namespace notstd {
template<class U>
struct moved_t {
U& u;
// relies on NRVO, which is pretty universally supported.
// also relies in U being default-constructible:
operator U()const{ U tmp; std::swap(u, tmp); return tmp; }
};
template<class U>
moved_t<U> move(U& u) { return {u}; }
template<class T>
struct unique_ptr {
unique_ptr( moved_t<unique_ptr<T>> > ); // move ctor
template<class U>
unique_ptr( moved_t<unique_ptr<U>> > ); // move ctor
private:
unique_ptr(unique_ptr const&);
};
}
This way your code will use notstd::unique_ptr<T>
. There would be no implicit rvalue conversion, so every place you move notstd::unique_ptr<T>
you need notstd::move
one.
Unfortunately, this means that it notstd::unique_ptr<T>
cannot be placed in containers std
. It might need to do some hacks to get them working (not safe auto_ptr
).
This is not a trivial task. boost::unique_ptr
was an attempt to generate unique unique_ptr semantics in C ++ 03 and they will do a better job than you most likely. If you can't use them directly, read what they did and override it yourself.
source to share