zoukankan      html  css  js  c++  java
  • [置顶]VC2013的一个bug

    [置顶]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是一个成员函数。

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


  • 相关阅读:
    web api post/put空值问题以及和angular的冲突的解决
    大话数据结构-图
    大话数据结构-树
    大话数据结构-栈与队列
    大话数据结构-线性表
    redis发布订阅、HyperLogLog与GEO功能的介绍
    redis使用管道pipeline提升批量操作性能(php演示)
    redis设置慢查询日志
    Laravel5.5配置使用redis
    Redis数据类型的常用API以及使用场景
  • 原文地址:https://www.cnblogs.com/xchsp/p/4272988.html
Copyright © 2011-2022 走看看