繁体   English   中英

std :: function的奇怪行为

[英]Strange behavior with std::function

我正在使用C ++ 11库中的标准函数包装器,我看到它的布尔运算符有一些奇怪的行为。 如果我创建一个std::function对象,则布尔运算符返回false。 如果我将nullptr分配给对象并再次检查,则仍然如此。 当我为它分配一个我已经转换为函数指针的void指针时出现问题。 考虑以下程序:

#include <functional>
#include <iostream>

void* Test() {
    return nullptr;
}

int main(int argc, char* argv[]) {
    std::function<void()> foo;
    std::cout << !!foo << std::endl;

    foo = nullptr;
    std::cout << !!foo << std::endl;

    foo = reinterpret_cast<void(*)()>(Test());
    std::cout << !!foo << std::endl;

    return 0;
}

我期望输出为0 0 0但结果是0 0 1 (见演示 )。 任何人都可以解释为什么布尔运算符在包含空的,不可调用的函数指针时返回true? 还请提一下在std::function检查nullptr的解决方法

注意:我已经尝试检查目标是否为null(使用foo.target<void*>() == nullptr )而不是使用布尔运算符,但似乎无论函数对象包含什么,目标始终为null(即使函数对象被调用完全正常)。

对我来说看起来像个错误。 首先,这是一个简单的例子 ,不播放任何带有强制转换的游戏:

#include <functional>
#include <iostream>

typedef void (*VF)();

VF Test() {
    return nullptr;
}

int main(int argc, char* argv[]) {
    std::function<void()> foo(Test());
    std::cout << !!foo << std::endl;
    return 0;
}

它仍然用GCC打印1。 它不应该:

20.8.11.2.1
template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
7 要求: F应为CopyConstructible 对于参数类型ArgTypesf应为Callable (20.8.11.2)并返回类型R 的拷贝构造函数和析构函数A不抛出异常。
8 后置条件: !*this如果满足以下任何条件:

  • f是一个NULL函数指针。
  • f是指向成员的NULL指针。
  • F是函数类模板的实例,并且!f

我不认为代码正在做你认为它做的事情。 这一行:

foo = reinterpret_cast<void(*)()>(Test());

表示您从Test()收到void* 然后,您继续将此指针指向对象 reinterpret_cast指向函数指针 这是不允许的,因此代码会产生未定义的行为,因此编译器的任何输出都是有效的。

标准的相关部分是

5.2.10重新解释强制转换[expr.reinterpret.cast]

8有条件地支持将函数指针转换为对象指针类型,反之亦然。 这种转换的含义是实现定义的,除非实现支持两个方向的转换,将一种类型的prvalue转换为另一种类型并返回,可能具有不同的cv-限定条件,将产生原始指针值。

9空指针值(4.10)将转换为目标类型的空指针值。 [ 注意: std::nullptr_t类型的空指针常量不能转换为指针类型,并且整数类型的空指针常量不一定转换为空指针值。 - 结束说明 ]

4.10指针转换[conv.ptr]

1 空指针常量是整数类型的整数常量表达式(5.19)prvalue,其计算结果为零或类型为std::nullptr_t 空指针常量可以转换为指针类型; 结果是该类型空指针值 并且可以与对象指针或函数指针类型的每个其他值区分开

(强调我的)

这是一个简化的测试用例,将std::function (及其可能的错误)排除在等式之外:

#include <iostream>

int main() {
    using fp_t = void(*)();
    void* vn = nullptr;
    fp_t foo = reinterpret_cast<fp_t>(vn); // GCC: warning, Clang: silence
    //fp_t foo = reinterpret_cast<fp_t>(nullptr); // error (GCC and Clang!)
    std::cout << !!foo << std::endl;
}

实例

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM