代码之家  ›  专栏  ›  技术社区  ›  Charles L Wilcox

这个失败的测试会给空指针未定义的行为、编译器错误或其他什么增加零吗?

  •  24
  • Charles L Wilcox  · 技术社区  · 6 年前

    string_view 一个C++ 14项目的包装器,用MSVC 2017触发 static_assert assert

    下面是代码:

    #include <cassert> // assert
    #include <cstddef> // size_t
    
    class String_View
    {
        char const* m_data;
        std::size_t m_size;
    public:
        constexpr String_View()
          : m_data( nullptr ),
            m_size( 0u )
        {}
    
        constexpr char const* begin() const noexcept
        { return m_data; }
        constexpr char const* end() const noexcept
        { return m_data + m_size; }
    };
    
    void static_foo()
    {
        constexpr String_View sv;
    
    //    static_assert( sv.begin() == sv.end() ); // this errors
        static_assert( sv.begin() == nullptr );
    //    static_assert( sv.end() == nullptr ); // this errors
    }
    
    void dynamic_foo()
    {
        String_View const sv;
    
        assert( sv.begin() == sv.end() ); // this compiles & is optimized away
        assert( sv.begin() == nullptr );
        assert( sv.end() == nullptr ); // this compiles & is optimized away
    }
    

    Compiler Explorer link 我曾经复制过这个问题。

    据我所知,加减法 0

    end 方法,则失败 s会过去的。

    constexpr char const* end() const noexcept
    { return ( m_data == nullptr
               ? m_data
               : m_data + m_size ); }
    

    我想也许 m_data + m_size 在事实发生之前 m_size == 0 结束 与荒谬的 return m_data + 0; 错误:-/

    更新:

    这看起来确实是一个在15.7和15.8之间修复的编译器错误。

    2 回复  |  直到 6 年前
        1
  •  14
  •   Shafik Yaghmour    6 年前

    这看起来像一个MSVC错误,C++ 14草案标准明确允许添加和减去值。 0 指向一个指针以与自身进行比较,从 [expr.add]p7 :

    如果在指针值上加上或减去值0,则结果将与原始指针值相等。如果两个指针指向同一个对象,或者两个指针都指向同一数组末尾的一个,或者两个指针都为空,并且两个指针相减,则结果比较等于转换为std::ptrdiff\t类型的值0。

    看起来像 CWG defect 1776 导致p0137调整 [expr.add]p7 明确地说 null pointer .

    [expr.add]p4 :

    当具有整数类型的表达式J被加到指针类型的表达式P或从中减去时,结果的类型为P。
    -如果P的计算结果为空指针值,而J的计算结果为0,则结果为空指针值。
    -否则,如果P指向具有n个元素的数组对象x的元素x[i],则表达式P+J和J+P(其中J具有值J)指向(可能是假设的)元素x[i+J],如果0¤i+j公司¤如果0,表达式P-J指向元素x[ij]¤伊吉¤n。 (4.3).
    -否则,行为未定义。

    this github issue this PR

    MSVC在这里是不一致的,因为它允许在常量表达式中加减零,就像gcc和clang一样。这是关键,因为 undefined behavior in a constant expression is ill-formed

    constexpr int *p = nullptr  ;
    constexpr int z = 0 ;
    constexpr int *q1 = p + z;
    constexpr int *q2 = p - z;
    

    gcc、clang和MSVC允许它是一个常量表达式( live godbolt example )尽管不幸的是,MSVC在允许非零值方面存在双重不一致性,但考虑到以下情况:

    constexpr int *p = nullptr  ;
    constexpr int z = 1 ;
    constexpr int *q1 = p + z;
    constexpr int *q2 = p - z;
    

    live godbolt ).

        2
  •  11
  •   Brian Bi    6 年前