• VC2013的一个bug


    前段时间在尝试使用一个C++的GUI库nana。这个库最大的特点在于使用现代C++风格去编写GUI程序,而不需要使用大量的比较丑陋的代码(如MFC中的各种宏),或者其它的非C++元素。这是一个比较新的库,作者是个中国人,有兴趣的朋友可以去试一试,由于使用大量的C++11特性,所以需要VC2013或者GCC4.7以上的编译器。使用过程中无意间发现了VC2013的一个重载决议(overload resolution)上的一个bug,这边贴出来跟大家分享一下,或许可以帮助大家少走点弯路。

    我写了以下简单的代码来重现这个问题:

    #include <iostream>
    #include <string>
    
    class foo{
    public:
        void bar(std::string = {});
    };
    
    void foo::bar(std::string str)
    {
        std::cout << str << std::endl;
    }
    
    int main()
    {
        foo  f;
        f.bar();
    }

    编译运行这段代码,弹出一个错误:

    image

    按照错误提示,可以找到对应的代码1168行:

    image

    也就是这一行:

    _DEBUG_POINTER(_Ptr);

    加个断点可以发现这里面_Ptr为空指针,所以导致程序crash。这个问题其实比较容易理解,写一个更简单的例子就可以发现问题:

    #include <string>
    
    int main()
    {
        std::string str = nullptr;
    }

    这段代码通过nullptr去初始化一个string,而这显然是错误的。

    但问题在于,在最初的那段代码中,

    void bar(std::string = {});

    这个函数声明明明是给了函数bar一个默认参数,使其构造出一个空字符串。但为什么会调用xstring中的1168行呢?也就是参数为一个指针的assign函数呢?

    经过多次试验以后发现,VC将上面这个声明理解为了:

    void bar(std::string = {nullptr});

    也就是用一个空指针去初始化一个string,从而导致了问题。同样的代码,在GCC4.8中是没有任何问题的。并且如果把

    void bar(std::string = {});

    改为:

    void bar(std::string = std::string());

    在VC2013里也没有问题了。这也就说明了VC2013在处理{}来初始化对象时的确存在重载决议的问题。

    之所以之前说这个问题比较隐蔽,是因为这种情况只出现在类的成员函数中,如果是普通函数,就没有这个问题:

    #include <iostream>
    #include <string>
    
    void func(std::string = {});
    
    int main()
    {
        func();
    }
    
    void func(std::string str)
    {
        std::cout << str << std::endl;
    }

    上面这段代码和刚开始那段代码几乎一样,唯一的不同在于func是一个普通函数,而bar是一个成员函数。

    不知道大家有没有遇到类似的问题?

  • 相关阅读:
    什么是跨域?什么是同源策略?如何解决
    安装路由的环境
    react的开发环境
    遍历列表,遍历对象,以及组件
    redux 状态管理工具
    react的钩子函数
    json-server
    react中的setState,受控组件和非受控组件以及组件的传值
    vue中的插槽
    react遍历列表
  • 原文地址:https://www.cnblogs.com/codemood/p/4241128.html
Copyright © 2020-2023  润新知