加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 为什么通过引用传递从std :: function派生的对象会导致程序

发布时间:2020-12-16 10:37:19 所属栏目:百科 来源:网络整理
导读:如果我通过引用将从std :: function派生的对象传递给另一个函数,则程序在运行时始终会因bad_function_call错误而崩溃.如下面的代码所示: #includefunctional#includeiostreamclass foo :public std::functionint(void) { public: int operator()(){return 1
如果我通过引用将从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()&gt ;,而不是一个返回1的. std :: function执行基于类型擦除的多态,而不是基于继承的多态.它可以存储任何可以调用,复制和销毁的东西.您可以按值传递它,并且存储的可调用对象将随之传递. 继承它往往不是你想要做的.

class foo {
  public:
    int operator()(){return 1;}
};

这可以转换为std :: function.实际上,通过此更改,您的代码可以编译并运行.

如果没有这个改变,它更喜欢cast-to-base并将对(空)base 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.C.如下所述,

void bar(std::function<int(void)> f)

这是有效的,因为编译器在“切片”到基类和使用转换构造函数之间进行选择,并且转换构造函数是C标准的首选.

void bar(std::function<int(void)> const& f)

这里不是首选,因为不需要进行转换,只需“将其视为基础”,这比在规则中构造新对象具有更高的优先级.

在我们传递lambda或“unparented”foo的情况下,“引用父类”的情况不可用,所以从我们的foo(或lambda)创建一个临时的std :: function并且f绑定到它.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读