C++ 将函数对象赋值给函数包装器后出现意外行为
我在一个应用程序中搜索一个bug,我最终修复了它,但没有完全理解。 可使用以下简单程序再现该行为:C++ 将函数对象赋值给函数包装器后出现意外行为,c++,c++11,object-slicing,C++,C++11,Object Slicing,我在一个应用程序中搜索一个bug,我最终修复了它,但没有完全理解。 可使用以下简单程序再现该行为: #包括 #包括 #包括 结构Foo { 虚int运算符()(void){return 1;} }; 结构栏:公共Foo { 虚拟int运算符()(void)重写{return 2;} }; int main() { std::shared_ptr p=std::make_shared(); std::cout指针的静态类型p是Foo 所以在这个声明中 f = *p; 左操作数*p的类型为Foo,
#包括
#包括
#包括
结构Foo
{
虚int运算符()(void){return 1;}
};
结构栏:公共Foo
{
虚拟int运算符()(void)重写{return 2;}
};
int main()
{
std::shared_ptr p=std::make_shared();
std::cout指针的静态类型p
是Foo
所以在这个声明中
f = *p;
左操作数*p
的类型为Foo
,即存在切片。这是常规切片,隐藏在std::function
和std::shared\u ptr
层下
f = *p;
是有效的,因为*p
是一个可调用的对象,具有适当的运算符()
,这是可以包装在std::function
中的内容之一
它不起作用的原因是它复制了*p
——这是一个Foo&
,而不是条&
对上一个示例的此改编将表现出相同的行为:
Bar b;
Foo& c = b;
std::function<int(void)> f1 = c;
std::cout << f1() << std::endl;
条b;
Foo&c=b;
std::函数f1=c;
std::cout对象切片发生在这里
点被赋予f=*p;
,p
是std::shared\u ptr
类型,那么*p
的类型是Foo&
(而不是条&
)。即使参数通过引用,但
4) 将*this
的目标设置为可调用的f
,就像执行函数(std::forward(f)).swap(*this);
请注意,上面的F
也被推断为Foo&
。通过值获取参数,对象切片发生,效果是F
是从*p
切片复制的Foo
类型的对象赋值的
模板
功能(F);
切片
这是一个切片的例子。
原因是std::function
的赋值运算符(也在另一个示例中演示),该运算符表示:
将*this的目标设置为可调用的f,就像执行
函数(std::forward(f)).swap(*this);。此运算符不
参与重载解析,除非f可为参数调用
类型Args…和返回类型R(从C++14开始)
如果简化并精简示例,您可以很容易地看到发生了什么:
Foo* p = new Bar;
Foo f;
f = *p;//<-- slicing here since you deref and then copy the object
一个更合适的解决方案也可以是只使用reference\u wrapper
:
f = std::ref(p);
我想知道你在std::function的内部会发生什么,它会导致调用Bar::opeeator()。赋值应该如何工作?@n.m.我没想到会发生什么,这是一个bug,我必须在一些不是我编写的代码中找到它。+1用于显示解决方法。然而,这段代码“简化”的原因是对于<代码> fof**p;可以使用更多的解释。抱歉,但我没有要求一个解决办法。正如我提到的,我修复了bug,实际上我是用lambda做的。我要求的是一个详细的解释。RabBID76当然,我提到了这些解决方案/解决方案主要是为了其他用户来这里。但是我会更新我的答案。短。
f = [p]{return (*p)();};
f = std::ref(p);