Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

macro for switching between auto_ptr and unique_ptr

In a project that still uses pre-C++11 I wanted to prepare the source for the switch by compiling with a C++11 compiler and fixing the errors. They consisted of

  • instances of std::auto_ptr<T> replaced with std::unique_ptr<T>
  • where necessary, wrapped the smart pointer with std::move()
  • some 0 and NULL replaced with nullptr

Now I want to switch back to a pre-C++ compiler and write a macro that can switch back the changes, so that, when the time for the final compiler switch is there, I simply remove the macro. I tried

#ifndef HAVE_CXX11
#define nullptr NULL
namespace std {
#define unique_ptr<exvector> auto_ptr<exvector>
}
#endif

(with exvector an example type used with the smart pointer) This and similar attempts don't work because macros can't change template types. I also used typedef with no better results.

Is this possible at all and, if so, how?

like image 349
rwst Avatar asked May 26 '15 15:05

rwst


People also ask

What replaces auto_ptr?

std::unique_ptr was developed in C++11 as a replacement for std::auto_ptr. unique_ptr is a new facility with similar functionality, but with improved security (no fake copy assignments), added features (deleters) and support for arrays. It is a container for raw pointers.

Why was auto_ptr removed?

Since the assignment-semantics was most-disliked feature, they wanted that feature to go away, but since there is code written that uses that semantics, (which standards-committee can not change), they had to let go of auto_ptr, instead of modifying it.

When was auto_ptr deprecated?

auto_ptr was fully removed in C++17.


2 Answers

I would introduce very explicit macros like

//Defines to overcome pre C++11 limitations regarding 
//std::auto_ptr and absence of 'good' move (i.e. std::move) semantics.
//Strictly post C++11 code should use std::unique_ptr and std::move explicitly.
//All other code should use the macros.
//If pre-C++11 ceases to be a target the macros may be replaced...
#ifdef HAVE_CXX11 //Or whatever...

#define UNIQUE_PTR_TYPE std::unique_ptr
#define MOVE_UNIQUE_PTR(PTR) std::move(PTR)

#else

#define UNIQUE_PTR_TYPE std::auto_ptr
#define MOVE_UNIQUE_PTR(PTR) (PTR)

#endif

Why? Because even a casual reader will see that some substitution is going on.

Yes the code will look ugly but a safe "not going to blow anyone's fingers off ugly". We're engineers not poets and that's our kind of beautiful!

However I have to say that I agree with the poster who thinks you should branch the code. This is not the only incompatibility and your code will become increasingly bloated and you might find you're doing more work (and introducing more errors) trying to make a single branch multi-target than branching.

Macros are wonderful things but anything of the form:

#define <common symbol> <something else>

needs to be 100% guaranteed benign "you don't need to know it was substituted" before it can be condoned.

I just don't think:

#define unique_ptr auto_ptr

Or anything else that makes this substitution invisible quite passes that test. unique_ptr and auto_ptr aren't the same and the whole point that auto_ptr is deprecated is because you need to be careful with it.

For the lulz (to bed in my point about invisible substitutes) try:

#define if(A) if(((A)&&rand()>128)||rand()>(RAND_MAX-128))

That should keep the feckers busy for the afternoon... The best bit is you haven't seeded with srand() the failures will be repeatable!

like image 157
Persixty Avatar answered Nov 15 '22 04:11

Persixty


For just nullptr and unique_ptr, this could work:

#ifndef HAVE_CXX11
  #define nullptr NULL
  #define unique_ptr auto_ptr
#endif

But I don't know how you plan to cope with the different semantics of unique_ptr and auto_ptr.

If you're willing to live with some undefined behaviour for a while (of the kind unlikely to cause actual issues), you could also provide your own std::move:

namespace std {

template <class T>
T& move(T &x) { return x; }

}

It's UB, because you're not allowed to add anything to namespace std. But if it's only a temporary measure, it should be safe (the pre-11 compiler is unlikely to have the name std::move).

like image 35
Angew is no longer proud of SO Avatar answered Nov 15 '22 03:11

Angew is no longer proud of SO