使用基类指针的右值引用的函数具有来自复制的派生类的指针

Eoi*_*oin 0 c++ pointers rvalue-reference

这是我的意思的一个简短的例子.我发现很难简洁地说出这个问题.

struct A {};
struct B : public A {};

void foo(A*&& ap)
{
    ap = nullptr;
}

int main()
{
    B b;

    A* ap = &b;

    foo(std::move(ap));
    std::cout << (ap == nullptr ? "null" : "not null") << std::endl;

    B* bp = &b;

    foo(std::move(bp));
    std::cout << (bp == nullptr ? "null" : "not null") << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我希望这会打印出来

null
null
Run Code Online (Sandbox Code Playgroud)

而是它打印

null
not null
Run Code Online (Sandbox Code Playgroud)

快速查看x86反汇编会显示不需要的复制,仅适用于以下B*情况:

lea         eax,[bp]  
push        eax  
call        std::move<B * &> (03E14BFh)  
add         esp,4  
mov         ecx,dword ptr [eax]                     << Unwanted copy
mov         dword ptr [ebp-0ECh],ecx                << occurs here
lea         edx,[ebp-0ECh]  
push        edx  
call        foo (03E14B5h)  
add         esp,4  
Run Code Online (Sandbox Code Playgroud)

有没有改变签名的解决方案foo?对于我可以改变的关于层次结构或foo函数的内容,我非常受外部API的限制.

Ker*_* SB 5

foo对一个人有所反对A*.你不给它一个A*,而是一个B*.这需要转换.甲临时 A*形成,绑定到右值引用,改变,最后被丢弃.原件B*永远不会受到影响.