C ++ / CLI compiler error when passing unique_ptr to a virtual function?

The code below works fine when compiling C ++, but causes (for example) access violation (System.AccessViolationException) when compiling as C ++ / CLI ( /clr). In both cases, the code is compiled and linked without errors or warnings ( /W4).

c->g(std::move(p)); (excerpt)

It seems that the problem is that the temporary unique_ptr is created when the argument is destroyed before the function is called. This occurs when invoking virtual functions ( C::gand C::k), but does not occur when invoking non-virtual functions ( C::hand ::g). It happens whether the calling code is part of an unmanaged class ( struct) or managed ( ref struct). This will not happen if I complete the class #pragma unmanaged. (Sample code is compiled as unmanaged C ++ only when only C ++ / CLI functions are not used).

To some extent related: Linker error when using unique_ptr in C ++ / CLI , but my code codes are excellent.

Question (s): Is this a bug in the compiler? If so, is this a known bug? If not, is this a known C ++ / CLI limitation? Or else, an error in the code? If this is an error or a compiler restriction, is there a way (preferably a simple) workaround without changing the function signature (as suggested in this answer )?

(Generated code: although I am familiar with assembler, I did not understand disassembling the compiled C ++ / CLI process shown by the debugger where there is a call to the virtual function. When debugging ends, entering all the unique_ptr properties, but not the function call. ..)

(Some background: calling code, managed classes, is intended as a bridge between C # code and unmanaged C ++ libraries.)

:
Microsoft Visual Studio Professional 2015 14.0.25425.01 3,
Visual Studio 2015 (v140)

Microsoft.NET Framework 4.6.01038
:
14.0.24720.00 1

#include <memory>
#include <iostream>
using namespace std;

struct A
{
    virtual ~A() { cout << "~A()" << endl; }
};

struct I
{
    virtual void g(std::unique_ptr<A> p) = 0;
};

struct C : public I
{
    virtual void g(std::unique_ptr<A> p) override { cout << "C::g()" << endl; }
    void h(std::unique_ptr<A> p) { cout << "C::h()" << endl; }
    virtual void k(std::unique_ptr<A> p) { cout << "C::k()" << endl; }
};

void g(std::unique_ptr<A> p) { cout << "g()" << endl; }

//#pragma unmanaged
/*public ref*/ struct B
{
    void bug(I * c) {
        std::unique_ptr<A> p(new A);
        c->g(std::move(p)); // *p destroyed before reaching g() when /clr
    }
    void bug2(C * c) {
        std::unique_ptr<A> p(new A);
        c->k(std::move(p)); // *p destroyed before reaching g() when /clr
    }
    void ok() {
        std::unique_ptr<A> p(new A);
        g(std::move(p));
    }
    void ok(C * c) {
        std::unique_ptr<A> p(new A);
        c->h(std::move(p));
    }
};
//#pragma managed

int main()
{
    auto b = /*gcnew*/ new B;
    b->ok();
    C c;
    b->ok(&c);
    b->bug(&c);
    b->bug2(&c);

    return 0;
}

: A (?) MS Visual Studio 2013 Update 1 (?).

+4

Source: https://habr.com/ru/post/1651120/


All Articles