c++ - 通过基类接受方法转发派生的 UniquePtr 的右值移动引用而不是复制
问题描述
似乎将对 a 的右值引用转发给采用基类std::unique_ptr<Derived>
的 a 的接受方法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 << "1\n";
auto integer = std::make_unique<int>();
Forwarder(std::move(integer));
// No assertion
std::cout << "2\n";
auto nonInheriting = std::make_unique<NonInheriting>();
Forwarder(std::move(nonInheriting));
// No assertion
std::cout << "3\n";
std::unique_ptr<Base> base = std::make_unique<Derived>();
Forwarder(std::move(base));
// Assertion
std::cout << "4\n";
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>
即消除转换和所有权转移,则没有断言。
推荐阅读
- android - Android 主项目 build.gradle 中的插件部分和缺少的模块
- android - 使用Android如何获取Java文件的最后修改时间戳?
- python - BeautifulSoup 和 Craiglist - 无法获取具有相同属性和结构的数据
- java - 如何使用firebase中的网站用户注册详细信息通过android应用登录用户?
- vue.js - 如何在点击时更改 Vuejs v-for 循环中的前置图标?
- python-3.x - Pandas,BeautifulSoup - 迭代和编写多个页面以实现卓越
- css - React Router 似乎阻止了自定义 CSS
- ios - 如果 memorylayout<>.stride 和 memorylayout<>.size 不同,则无法构建?
- elixir - 如何在不经过常规登录过程的情况下使用 Wallaby 登录用户?(设置 cookie/会话)
- spring - Spring Boot REST API 版本控制的自定义标头方法