1

I'm catching a compile warning under Cygwin with -std=c++11:

cryptlib.cpp: In member function ‘virtual size_t PK_Signer::SignMessage(RandomNumberGenerator&, const byte*, size_t, byte*) const’:
cryptlib.cpp:770:41: warning: ‘auto_ptr’ is deprecated (declared at /usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/backward/auto_ptr.h:87) [-Wdeprecated-declarations]
std::auto_ptr<PK_MessageAccumulator> m(NewSignatureAccumulator(rng));
                                       ^

I tried adding:

#if defined(MYLIB_CXX11)
using auto_ptr = std::unique_ptr;
#else
using std::auto_ptr;
#endif

auto_ptr<PK_MessageAccumulator> m(NewSignatureAccumulator(rng));

But it resulted in the following, even with <memory> included.

$ make cryptlib.o 
c++ -std=c++11 -DNDEBUG -g2 -O3 -fPIC -march=native -DCRYPTOPP_DISABLE_ASM -Wall -Wextra -pipe -c cryptlib.cpp
cryptlib.cpp:770:27: error: no type named 'unique_ptr' in namespace 'std'
    using auto_ptr = std::unique_ptr;
                     ~~~~~^

I also tried variations of the following:

#if defined(MYLIB_CXX11)
typedef std::unique_ptr<T> local_ptr<T>;
#else
typedef std::auto_ptr local_ptr;
#endif

I can't make a clean cut-over to unique_ptr because its a C++03 library, and C++03 lacks unique_ptr. And I can't allow the dirty compile to continue under C++11 because clean compiles are a security gate, and governance will not allow the library to pass. (And warning tricks are out of the question because this is should be simple, low hanging fruit. Warning tricks include disabling the warning).

Is it possible to use "using" to swap in unique_ptr? Or is there some other mechanism?

jww
  • 97,681
  • 90
  • 411
  • 885
  • If the code is under your control, can it be recompiled given the C++03 vs C++11 support your require? See my update below. – Niall Jul 27 '15 at 10:38
  • Your typedefs don't work, because they relate to templates, not types. However, you can make this work in a very similar way, see my answer. – Walter Jul 27 '15 at 12:35

3 Answers3

3

I tried adding:

using auto_ptr = std::unique_ptr;
using std::auto_ptr;
auto_ptr<PK_MessageAccumulator> m(NewSignatureAccumulator(rng));

But it resulted in the following, even with included.

cryptlib.cpp:770:27: error: no type named 'unique_ptr' in namespace 'std'

That's because std::unique_ptr is a template, not a type. Instead, this should work

#if __cplusplus >= 201103L
  // with C++11 we have std::unique_ptr (and std::auto_ptr is deprecated)
  template<typename T>
  using auto_ptr = std::unique_ptr<T>;
#else
  // assuming C++03 when there is std::auto_ptr
  using std::auto_ptr;
#endif

(requires that you use merely auto_ptr in your code, rather than std::auto_ptr).


Of course, I am assuming that you use a valid C++ compiler and standard library. On Mac OS, you can use (you may need to install Xcode and command-line tools)

/usr/bin/c++ -std=c++11 -stdlib=libc++

which invokes the clang C++ compiler and the clang C++ standard library.

Walter
  • 44,150
  • 20
  • 113
  • 196
  • Man, I could scream... `using auto_ptr = std::unique_ptr;` does not work on Apple because its in the `std::tr1` namespace.... – jww Jul 27 '15 at 13:41
  • My C++03/C++11 saga continues... [How to guard for TR1 on Apple platforms for both C++03 and C++11?](http://stackoverflow.com/q/31655462). If I could test this, I would move the accepted answer... F***k'ing Apple and their junk... – jww Jul 27 '15 at 14:15
  • 2
    I'm not positive what "it" is, but neither `auto_ptr` nor `unique_ptr` were ever in `std::tr1` on Apple tools. – Howard Hinnant Jul 27 '15 at 14:17
  • @jww Could you perhaps produce a minimal reproducible (on MAC OS X) code example, so that we can understand your problem better? Or, alternatively, explain the problem better. – Walter Jul 27 '15 at 17:43
  • 2
    The error with `using auto_ptr = std::unique_ptr;` has **nothing to do with TR1**. It's because you're using the ancient libstdc++ on Mac OS X which does not provide `unique_ptr`. Simply saying `-std=c++11` does not magically make a libstdc++ from 2007 support new features added after 2007. – Jonathan Wakely Jul 27 '15 at 18:36
  • This is where most of the problem was, and why my wires were so crossed: ***`-std=c++11` does not magically make a libstdc++ from 2007 support new features added after 2007.*** The compiler should have produced an error. Don't f**k'ing lie to me about it.... I can't tell you how many hours I wasted on it because I thought the problem was with me (which it usually is). – jww Jul 27 '15 at 21:30
2

Understanding that the code is under your control and can be recompiled with or with out C++11 support, an alias can be created for the smart pointer required (either std::unique_ptr or std::auto_ptr).

template <typename T>
struct local_ptr {
    #if defined(MYLIB_CXX11)
    typedef std::unique_ptr<T> ptr;
    #else
    typedef std::auto_ptr<T> ptr;
    #endif
};

Then used in the client code as such;

local_ptr< PK_MessageAccumulator>::ptr managed = //...

The syntax is more awkward than desired, but this is to accommodate the requirement to support C++03.

In all cases, the long term solution is to factor out the use of auto_ptr or silence the deprecated warnings.

Niall
  • 30,036
  • 10
  • 99
  • 142
  • Thanks Niali. It looks a lot like [Typedef a template class without specifying the template parameters](http://stackoverflow.com/q/1474417/608639). For some reason, I thought there was a more elegant solution in C++ 11. – jww Jul 27 '15 at 11:30
  • 1
    There are "template aliases" in C++11, but they won't compile in C++03 `template using ptr = std::unique_ptr;`. In general, code required to be compatible with C++03 reverts to old style code - not necessarily bad, just the way it is. – Niall Jul 27 '15 at 11:33
  • This requires changes to the code wherever `std::auto_ptr` was used. I don't think that's necessary, see my answer below. – Walter Jul 27 '15 at 11:51
1

You have two options.

  • Use auto_ptr in your application, and leave the library as it is. Deprecation warnings will not prevent the application from working correctly, they are only there to help.

  • Use unique_ptr in your application, and modify the library to use unique_ptr as well.

You can't mix them. If you can't modify the library, then you will be forced to use auto_ptr in your code.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • Thanks Dietrich. I control the library and the application. When C++11 is in effect, I want to use `unique_ptr`. When C++03 is in effect, I want to use `auto_ptr`. (I'm not sure you captured that use case above). – jww Jul 27 '15 at 06:30
  • 1
    So, to be clear, are you saying that you want to make a library where it uses `unique_ptr` everywhere with C++11, but `auto_ptr` with C++03? Because you can't use `auto_ptr` in the library but `unique_ptr` in the application which uses it. – Dietrich Epp Jul 27 '15 at 06:33
  • @jww You're better off disabling the warning. Even if you managed to get the alias template to work, what would be the point of having code that potentially behaves differently in C++03 and C++11? – juanchopanza Jul 27 '15 at 07:06