似乎将右值引用转发到std::unique_ptr<Derived>
到接受方法,const std::unique_ptr&
基类会导致 std::unique_ptr 被移出。对于数字或非继承类,不会发生这种情况。
最初是在MSVC++ 2019上发现的,但也在各种其他编译器上进行了测试,这些编译器都给出了相同的结果。这种行为是否符合标准?
#include <memory>
#include <cassert>
#include <iostream>
class Base
{};
class Derived : public Base
{};
class NonInheriting
{};
void Corrupter(const std::unique_ptr<Base>&)
{}
void Corrupter(const std::unique_ptr<int>&)
{}
void Corrupter(const std::unique_ptr<NonInheriting>&)
{}
void Usage(std::unique_ptr<Base>&& base)
{
assert(base);
}
void Usage(std::unique_ptr<int>&& base)
{
assert(base);
}
void Usage(std::unique_ptr<NonInheriting>&& base)
{
assert(base);
}
template<class... Args>
void Forwarder(Args&& ... args)
{
Corrupter(std::forward<Args>(args)...);
Usage(std::forward<Args>(args)...);
}
int main()
{
// No assertion
std::cout << "1n";
auto integer = std::make_unique<int>();
Forwarder(std::move(integer));
// No assertion
std::cout << "2n";
auto nonInheriting = std::make_unique<NonInheriting>();
Forwarder(std::move(nonInheriting));
// No assertion
std::cout << "3n";
std::unique_ptr<Base> base = std::make_unique<Derived>();
Forwarder(std::move(base));
// Assertion
std::cout << "4n";
auto derived = std::make_unique<Derived>();
Forwarder(std::move(derived));
return 0;
}
这是预期行为。
对于第 4 种情况,您传递了一个std::unique_ptr<Derived>
,Forwarder
它传递给Corrupter
,后者期望std::unique_ptr<Base>
。std::unique_ptr<Derived>
可以隐式转换为std::unique_ptr<Base>
,然后将参数args
转换为std::unique_ptr<Base>
,指针的所有权也转移到临时std::unique_ptr<Base>
,args
现在一无所有。之后,它被传递给Usage
然后触发断言。
在其他情况下,没有发生转换和所有权转让,那么他们就没有这样的问题。
如果您添加另一个Corrupter
的重载,std::unique_ptr<Derived>
,即消除转换和所有权转让,则没有断言。
住