C++ std:.auto_ptr or std::unique_ptr (to support multiple compilers, even old C++03 compilers)?

ε祈祈猫儿з 提交于 2019-12-07 22:10:42

问题


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:

  1. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!