为什么(成员)函数指针行为在Visual C如此古怪++?(Why are (member) fun

2019-07-17 21:05发布

我有,我已经减少到了下面的测试情况下,真正奇怪的问题:

#include <iostream>
#include <map>
#include <string>

struct Test
{
    std::map<std::string, void (Test::*)()> m;
    Test()
    {
        this->m["test1"] = &Test::test1;
        this->m["test2"] = &Test::test2;
    }
    void test1() { }
    void test2() { }
    void dispatch(std::string s)
    {
        if (this->m.at(s) == &Test::test1)
        { std::cout << "test1 will be called..." << std::endl; }
        else if (this->m.at(s) == &Test::test2)
        { std::cout << "test2 will be called..." << std::endl; }
        (this->*this->m.at(s))();
    }
};

int main()
{
    Test t;
    t.dispatch("test1");
    t.dispatch("test2");
}

它输出

test1的将被称为...
test1的将被称为...

启用优化时,这是非常奇怪的。 这是怎么回事?

Answer 1:

这是什么的Visual C ++是指作为相同COMDAT折叠 (ICF)的副产物。 它合并相同功能集成在单一实例。 可以通过添加以下开关到链接器命令行停用: /OPT:NOICF (从它被下属性- >连接器- > Optimization-发现>在Visual Studio UI 启用COMDAT折叠

您可以在MSDN文章在这里的细节: / OPT(优化)

所述开关是连接基级开关,这意味着你将无法以使它只为特定模块或代码的特定区域(如__pragma( optimize() )其可用于编译阶段优化)。

但一般情况下,它被认为是不良的做法依赖于两个函数指针或文字字符串指针( const char* )进行测试的唯一性。 串折叠是由几乎所有的C / C ++编译器广泛实施。 功能折叠只在VISUAL C ++,此时可用,虽然增加了广泛的使用模板的<>元编程增加了请求,此功能将被添加到gcc和铿锵工具链。

编辑:有binutils的2.19开始,包括金连接器据称还支持ICF,但我一直无法证实它在我的本地的Ubuntu 12.10安装。



Answer 2:

原来的Visual C ++的接头可以合并相同的定义功能于一体。
不管是合法或不按照C ++,我不知道; 它会影响观察到的行为,所以它看起来像我的错误。 别人更多的信息可能要附和上,虽然。



Answer 3:

C ++ 11 5.3.1描述了&做; 在这种情况下,它给你的指针有问题的成员函数,并且通道不作任何要求,这个指针必须是唯一的。

然而,5.10 / 1说,大约==

同一类型的两个指针比较,如果相同且仅当它们都为null,都指向相同的功能,或两者都代表相同的地址。

现在的问题就变成了...是test1test2 “同样的功能”?

虽然优化了它们压缩成一个单一的定义,可以说是两个人的名字确定两个函数和,因此, 这似乎是一个执行错误

(请注意,虽然,森林狼队并不关心,并认为这是“足够有效”,以保证优化的好处。那,或者他们没有意识到这是无效的 。)

我会坚持使用字符串为“手柄”你的函数指针。



文章来源: Why are (member) function pointers behaving so weirdly in Visual C++?