为什么通过引用传递从 std::function 派生的对象会使程序崩溃?
Why passing an object derived from std::function by reference crashes the program?
如果我通过引用将派生自 std::function 的对象传递给另一个函数,程序在运行时总是崩溃并出现bad_function_call错误。如以下代码所示:
#include<functional>
#include<iostream>
class foo :public std::function<int(void)> {
public:
int operator()(){return 1;}
};
void bar(const std::function<int(void)>& f) {std::cout << f() << std::endl;}
int main(){
foo f;
bar(f);
}
但是,如果函数对象按值传递,如下所示:
void bar(std::function<int(void)> f)
程序运行正常。我已经在gcc,clang和Visual Studio上测试了该程序,结果是一样的。是什么导致了这种bad_function_call?
std::function::operator()
不是虚拟的。
class foo :public std::function<int(void)> {
public:
int operator()(){return 1;}
};
将foo
视为std::function
时,您编写的operator()
没有任何作用。 你有一个空的std::function<int()>
,而不是返回 1 的空。
std::function
执行基于类型擦除的多态性,而不是基于继承的多态性。 它可以存储任何可以调用、复制和销毁的内容。 您可以按值传递它,存储的可调用对象将随之而来。
从中继承通常不是您想要做的。
class foo {
public:
int operator()(){return 1;}
};
这可以转换为std::function
。 事实上,通过此更改,您的代码可以编译和工作。
如果没有此更改,它更喜欢强制转换为基数,并将对(空)基std::function
的引用传递给参数。 如果没有继承,它会尝试将foo
转换为std::function
并成功。
当然,这个foo
很愚蠢。
取而代之的是:
int main(){
foo f;
bar(f);
}
我们可以这样做:
int main(){
auto f = []{ return 1; };
bar(f);
}
而且效果也很好。 (上面的 lambda 自动生成一个类,该类在重要方面与上面的foo
类型几乎相同。 它也不会继承自std::function
。
C++支持多种多态性。 基于继承的多态性(很容易)不允许值类型,并且C++在值类型上蓬勃发展,因此编写std::function
是为了处理值类型。
如下@T所述,
void bar(std::function<int(void)> f)
这是有效的,因为编译器在"切片"到基类和使用转换构造函数之间进行选择,并且转换构造函数是C++标准的首选。
void bar(std::function<int(void)> const& f)
这里不是首选,因为不需要进行转换,只需"视为基础",这比在规则中构造新对象的优先级更高。
在我们传递 lambda 或"非父级"foo 的情况下,"引用父级"的情况不可用,因此从我们的foo
(或 lambda)创建一个临时std::function
并f
绑定到它。
你的重载没有被使用,常量一个(from std::function
)与const std::function<int(void)>& f
一起使用。 由于您不初始化std::function
,它是空的,然后在调用operator ()
时抛出。
按值传递时,将从函子(与任何常规函子一样)创建一个std::function
,然后std::function
调用存储的函子。
但不要从std::function
派生,只是使用
auto f = [](){ return 1; };
bar(f);
bar(f);
您正在将类型foo
的f
传递给bar
,但bar
的参数const std::function<int(void)>
在这里,foo
被上升为常量std::function<int(void)>
。
您没有在const std::function<int(void)>
中重载运算符()。
所以它抛出运行时错误。
- 我有一个对象,它将在整个程序的持续时间内实例化,但一个类成员不会,我应该动态分配它吗?
- 内存清理程序报告全局对象构造中未初始化值的使用
- 程序如何'remember'临时对象?
- 什么是"undetectable means",它们如何更改 C/C++ 程序的对象?
- 是否可以使用非常量指针调用非常量函数,以及当两个unique_ptrs指向同一个对象时程序的行为方式?
- 将FFMpeg AVFrame对象从C++应用程序流式传输到Python的最佳方法?
- 将 C# 对象(包含静态对象成员)作为参数传递给 C++/CLI 程序
- C++,在对象内分配多个数据时,堆栈分配是否更有效? 在下面的程序中,类A_Heap的效率会更低吗?
- 通过 COM 对象连接 x64 应用程序时出现问题
- 修改多线程应用程序中的对象
- 无法在需要对象展开修复程序的函数中使用__try
- 在C++面向对象程序中,谁负责删除传递给构造函数的对象
- 将文件从 iOS 应用程序加载到 C++ 对象中/<iostream>iOS 上的问题
- 运行程序时找不到共享对象库,但在编译过程中链接了它
- 在C++中,系统如何将这些对象中的每一个与执行程序的窗口相关联?
- OpenGL和面向对象程序结构
- C++面向对象程序和PHP面向对象程序之间的区别
- C++面向对象程序中的获取和设置方法
- 我编写了一个小的面向对象程序,我不知道为什么它不能编译
- C++面向对象程序复制了继承模式