0

Consider the following code:

#include <memory>

struct A {};

struct B : public A {};

void func( std::auto_ptr< A > ptr ) {}

int main() {
    std::auto_ptr< B > b( new B() );
    func( b );
}

I know that auto_ptr is removed in C++17 and was deprecated for a long time, however, I am using boost-python, which does not support unique_ptr in its interfaces (e.g., see this). I am using g++ 7.5.

Due to the conversion constructor defined by auto_ptr (see (3)), implicit conversion should be possible. However, I get the error:

error: conversion from ‘std::auto_ptr’ to ‘std::auto_ptr’ is ambiguous

If I use unique_ptr instead, which defines a similar constructor (see (6)), I get a similar error:

error: could not convert ‘b’ from ‘std::unique_ptr’ to ‘std::unique_ptr’

Why is that?

theV0ID
  • 4,172
  • 9
  • 35
  • 56
  • 2
    For `std::unique_ptr`: it would be `func( std::move(b) );`... but missing virtual destructor in `A`. – Jarod42 Jun 01 '21 at 10:45
  • @Jarod42 OK thanks, this clears things up. However, I would still expect `auto_ptr` to work without the move semantics? – theV0ID Jun 01 '21 at 10:47
  • How about `std::shared_ptr` if you need copy semantic? – Jarod42 Jun 01 '21 at 10:48
  • Being explicit on the conversion [pass](http://coliru.stacked-crooked.com/a/7e3a852fc2b76f77) (`func( std::auto_ptr< A >(b) );`) – Jarod42 Jun 01 '21 at 10:49
  • I actually need move semantics (at least I think this is what it is called). To be precise, what I need, is what [constructor (3) of auto_ptr](https://en.cppreference.com/w/cpp/memory/auto_ptr/auto_ptr) does: *"Constructs the auto_ptr with the pointer held in r. **r.release() is called to acquire the ownership of the object.**"* – theV0ID Jun 01 '21 at 10:50
  • According to [this answer](https://stackoverflow.com/a/58181162/10871073), the `*_ptr` argument to `func` must be an rvalue. Changing the signature to `void func(std::auto_ptr< A > &&ptr)` resolves the issue. – Adrian Mole Jun 01 '21 at 10:51
  • Yes being explicit works, but why does implicit conversion not work? – theV0ID Jun 01 '21 at 10:51
  • @AdrianMole Changing the signature works only with explicit conversion, but not with implicit? http://coliru.stacked-crooked.com/a/c26154dbe50bc526 – theV0ID Jun 01 '21 at 10:54
  • My bad - MSVC accepts the implicit conversion (but clang-cl doesn't). – Adrian Mole Jun 01 '21 at 10:59
  • The compiler writes ambiguous candidates in the error message: `operator auto_ptr<_Tp1>()` and `auto_ptr(auto_ptr<_Tp1>& __a)`. unique_ptr does not define implicit [conversion operator](https://en.cppreference.com/w/cpp/memory/auto_ptr/operator_auto_ptr), so the conversion is ambiguous for it. – dewaffled Jun 01 '21 at 11:18
  • @dewaffled Maybe I am missing the point, but as far as I see from the two candidates, both are valid conversions and I'd be fine with either. How to make it work for the `auto_ptr`? – theV0ID Jun 01 '21 at 11:24
  • There is no way to make it work implicitly, use one of the workaround presented above. But the bigger issue is that Boost.Python isn't maintained anymore and `auto_ptr` is a very dangerous and clunky thing that is gone from C++ now and should never be used. Might want to give [pybind11](https://github.com/pybind/pybind11) a try instead (although I don't know if it supports unique_ptr). – rustyx Jun 01 '21 at 13:48
  • This obviously doesn't answer the question, but I wonder why this is not std::auto_ptr< A > b( new B() ); ? Afterall the all point of hierarchy is acting polymorphically. – Alessandro Teruzzi Jun 01 '21 at 13:49

1 Answers1

0

It appears that the compiler thinks that it is ambiguous, because the operator() conversion and constructor type conversion are ranked the same in auto_ptr. The compiler error says it quite clearly that it couldn't pick between the 2 conversions:

../src/test_curl_pop3.cpp:26:10: error: conversion from ‘std::auto_ptr<B>’ to ‘std::auto_ptr<A>’ is ambiguous
  func( b );
          ^
In file included from /usr/include/c++/5/memory:85:0,
                 from ../src/test_curl_pop3.cpp:9:
/usr/include/c++/5/backward/auto_ptr.h:279:9: note: candidate: std::auto_ptr< <template-parameter-1-1> >::operator std::auto_ptr<_Up>() [with _Tp1 = A; _Tp = B]
         operator auto_ptr<_Tp1>() throw()
         ^
/usr/include/c++/5/backward/auto_ptr.h:125:9: note: candidate: std::auto_ptr< <template-parameter-1-1> >::auto_ptr(std::auto_ptr<_Up>&) [with _Tp1 = B; _Tp = A]
         auto_ptr(auto_ptr<_Tp1>& __a) throw() : _M_ptr(__a.release()) { }
         ^
../src/test_curl_pop3.cpp:20:6: note:   initializing argument 1 of ‘void func(std::auto_ptr<A>)’
 void func( std::auto_ptr<A> p ) {}
surfcode
  • 445
  • 1
  • 5
  • 20