问题
I'm trying to update some C++ code, I'd like to move toward a more modern code (c++11), but I still need to compile the code with some older compilers (c++03 compliant), because of supported platform constraints.
I know in C++11 compilers std::auto_ptr is deprecated, but because of the older compiler support, I can't just replace them with std::unique_ptr.
Is there a good practice to handle this "old compiler support, but start to move to C++11"?
回答1:
As you noted, std::auto_ptr<> has been deprecated in C++11 (Reference).
Moving to c++11 std::unique_ptr<> is the right way, as also stated by Herb Sutter in GotW89:
- What’s the deal with auto_ptr?
auto_ptr is most charitably characterized as a valiant attempt to create a unique_ptr before C++ had move semantics. auto_ptr is now deprecated, and should not be used in new code.
If you have auto_ptr in an existing code base, when you get a chance try doing a global search-and-replace of auto_ptr to unique_ptr; the vast majority of uses will work the same, and it might expose (as a compile-time error) or fix (silently) a bug or two you didn’t know you had.
Please also note that C++17 is going to remove std::auto_ptr.
I think there may be different ways of solving your problem, the "right" one also depends on how your actual code is written.
A few options are:
Option 1
Use boost::unique_ptr
Option 2
Conditionally 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 in every place where you reference auto_ptr, I don't really like it.
May be look less awkward if all your references to std::auto_ptr are already typedef'ed (just conditionally change the typedef).
Option 3
Conditionally use using and aliasing to "define" auto_ptr (and reference it without std:: namespace).
#if __cplusplus < 201103L
using std::auto_ptr;
#else
template
using auto_ptr = std::unique_ptr;
#endif
Drawback: you keep using "auto_ptr", but in c++11 it means std::unique_ptr.
Really confusing...
Option 3.1
Probably slightly better than option 2:
reverse using aliases and prefer unique_ptr name.
Option 4
Wrap the std:: smart pointer (conditionally auto_ptr or unique_ptr) in your own defined template smart pointer class.
This may be cumbersome and requires search and replacement of all auto_ptr references with your new class.
Other dirty options
Other options involve definitions inside the std:: namespace, which I think is prohibited by the standard,
or using preprocessor #define to ...ehm... "rename" unique_ptr to auto_ptr just for old C++03 compilers.
回答2:
In this exact case you can start modernizing your code by using boost::unique_ptr
instead of auto_ptr
, which is not recommended.
Overall, big part of C++11 libraries is straight-up taken from boost, so it will be good place to start.
回答3:
If I was serious, I'd create a notstd
namespace.
The goal would be that in C++11, notstd
consists of a series of aliases to std
types. In C++03, it has pseudo-C++11 code.
The C++03 notstd
code would not be 100% compatible with C++11 std
, but rather valid C++03 notstd
would in turn produce valid C++11 behavior.
For example, I might use special tagged "reference-wrapper" like types for notstd::move
references instead of rvalue references, and have my move-only types require such tagged "reference-wrapper"s.
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&);
};
}
So your code would use notstd::unique_ptr<T>
. There would be no implicit rvalue conversion, so every spot where you move a notstd::unique_ptr<T>
you'd have to notstd::move
it.
Sadly this means notstd::unique_ptr<T>
cannot be put into std
containers. Some hack may have to be done to get that to work (neither can auto_ptr
safely).
This is a non-trivial task. boost::unique_ptr
was an attempt to generate unique_ptr like semantics in C++03, and they are going to do a better job than you will most likely. If you cannot use them directly, read up on what they did and reimplement it yourself.
来源:https://stackoverflow.com/questions/40893636/c-std-auto-ptr-or-stdunique-ptr-to-support-multiple-compilers-even-old-c