Why is struct with auto_ptr and explicit destructor unable to replace

look at this code. Test struct has auto_ptr and an explicit destructor. When I generate this code in Windows environment (Visual Studio 2017 Professional) with error level 4 , it shows this warning.

warning C4239: nonstandard extension used: 'argument': conversion from 'Test' to 'Test &' note: A non-const reference may only be bound to an lvalue; copy constructor takes a reference to non-const

I understand that it std::swap

accepts a reference for a class Test

and cannot use an instance for a reference. If I remove the destructor or auto_ptr the warning goes away. Any idea what the reason is?

#include <algorithm>
#include <memory>
typedef struct Test
{
public:
    int a;
    std::auto_ptr<Test> b;
    ~Test()
    {
    }
} Test_Type;


int main()
{
    Test_Type arr[2];
    arr[0].a = 5;
    arr[1].a = 3;
    std::swap(arr[0], arr[1]);
}

      

+3


source to share


1 answer


auto_ptr

is strange because its "copy" constructor takes the source with a non-const reference, since it needs to modify it.

This forces the Test

implicitly declared copy constructor to also grab the source using reference <<22>.

A user-declared destructor suppresses the implicit declaration of a move constructor.

So internally swap

, when it does the equivalent Test_Type tmp = std::move(arr[0]);

, the only constructor available is the copy constructor accepting a non-const reference, and the only reason a constructor might even be used is the non-standard extension mentioned in the warning allowing such a reference to bind to the value r ...



Take out auto_ptr

, and the Test

implicitly declared constructor will now take the reference const

that binds to the rvalues.

Take out the destructor and Test

will now have an implicit move constructor that you can use to move.

Note that the move constructor Test

may unexpectedly not be implicitly defined as being deleted. While it auto_ptr

does not have a move constructor, the test is whether the overload resolution for direct initialization from rvalues ​​has auto_ptr

. This is due to teninagam auto_ptr_ref

. Both Clang and GCC got it wrong, while MSVC got it right (!).

All of the above applies to the assignment operator.

+2


source







All Articles