代码之家  ›  专栏  ›  技术社区  ›  sharptooth

C++标准究竟在哪里声明未初始化指针是未定义的行为?

  •  11
  • sharptooth  · 技术社区  · 15 年前

    int* ptr;
    *ptr = 0;
    

    是未定义的行为。

    首先,有5.3.1/1声明 * 意思是间接的改变 T* T . 但这并不能说明UB。

    然后经常引用3.7.3.2/4,说在非空指针上使用deallocation函数会使指针无效,以后使用无效指针是UB。但是在上面的代码中没有关于释放的内容。

    如何在上面的代码中推断UB?

    7 回复  |  直到 15 年前
        1
  •  12
  •   JUST MY correct OPINION    15 年前

    第4.1节看起来像候选人( 强调我的

    a的左值(3.10) 非函数,非数组类型T可以是 不完整类型,一个程序 这种转变是必要的 形式不良。如果 左值引用不是类型的对象 来源于T,或 如果对象是 未初始化 ,一个程序 必须进行这种转换 . 如果T是 是不合格的简历版本。 否则,rvalue的类型是 T。

    我相信只要在规范中搜索“uninitial”就可以找到更多的候选人。

        2
  •  6
  •   Nathan S.    12 年前

    我发现这个问题的答案是 C++ draft standard 24.2 迭代器需求 24.2.1 一般来说 段落 10个 强调我的 ):

    未初始化指针 x(如int*x;),x . 结束示例][…] 可解引用的值总是非奇异的。

    以及:

    268个

    和脚注 268

    这个定义适用于指针, 因为指针是迭代器

    虽然看起来确实有一些争议 whether a null pointer is singular or not 看起来这个词 需要以更一般的方式正确定义。

    目的 似乎在缺陷报告中总结得很好 278. What does iterator validity mean? 在“基本原理”一节中:

    “可能是单数的” 有效迭代器是已知的非奇异迭代器 . 使迭代器失效意味着以一种不再被认为是非奇异的方式改变它。一个例子:将一个元素插入到向量的中间被正确地说成是使指向向量的所有迭代器失效。那个 并不一定意味着它们都会变得单一 .

    所以 以及存在 未初始化 may 创建一个值 但既然我们不能证明他们是 我们必须假设他们是 单数的

    更新

    另一种常识方法是注意到标准节草案 5.3.1 一元运算符 1个 上面写着( 强调我的 ):

    一元*运算符执行间接寻址:应用它的表达式应是指向对象类型的指针,或指向函数类型的指针,并且 结果是引用对象的左值

    如果我们去部门 3.10 左值和右值 1个 说( 强调我的 ):

    但是 ptr 除非偶然,否则不会指向 对象 .

        3
  •  5
  •   Yttrill    15 年前

    该标准界定了某些行为。问题是,在这种情况下,它是否规定了任何行为?如果它没有,那么无论它是否明确表示,行为都是不确定的。

    事实上,标准中保留了一些东西未定义的规范,主要是作为标准编写者的调试辅助工具,其思想是,如果某个地方的要求与另一个地方未定义行为的明确声明相冲突,则会产生矛盾:这是证明标准缺陷的一种方法。如果没有对未定义行为的明确陈述,另一个规定行为的条款将是规范的,不受质疑的。

        4
  •  3
  •   Maiku Mori    15 年前

    我不会假装对此了解很多,但有些编译器会将指针初始化为NULL,并取消对指向NULL的指针的引用。

    第8.3.2节中的注释[dcl.ref]

    [注:特别是空引用 程序,因为 创建这样的引用将是 将其绑定到通过 取消对空指针的引用,该指针 . 作为 直接绑定到位字段。]

    ISO/IEC 1488∶1998(E),ISOC++标准,在第8 3.2节[DCL,REF]

    我想我应该写这篇评论来代替,我不太确定。

        5
  •  3
  •   Gunther Piez    15 年前

    要解引用指针,需要读取指针变量(而不是它指向的对象)。读取未初始化的变量是未定义的行为。

        6
  •  3
  •   M.M    11 年前

    评价 未初始化的指针导致未定义的行为。由于取消引用指针首先需要对其求值,这意味着取消引用也会导致未定义的行为。

    在C++ 14中,它完全被[dCL init ] / 12覆盖:

    获取具有自动或动态存储持续时间的对象的存储时,该对象有一个不确定值,如果不对该对象执行初始化,则该对象将保留一个不确定值,直到该值被替换为止。

    如果求值产生不确定值,则行为未定义,但在以下情况下除外:

    unsigned char .


    在C++ 11中,[Vang.LVAL/2 ]将此值覆盖在LValt到RValf转换过程中(即从 ptr ):

    非函数、非数组类型T的glvalue可以转换为prvalue。如果T是不完整类型,则需要此转换的程序是格式错误的。如果glvalue引用的对象不是 或者如果对象未初始化, 需要此转换的程序具有未定义的行为。

    为C++ 14删除了带螺栓的部分,并用[dCL init/12 ]中的额外文本替换。

        7
  •  1
  •   supercat    11 年前

    即使在内存中正常存储的某些东西对于任何陷阱位或陷阱表示没有“空间”,实现也不需要像静态持续时间变量那样存储自动变量,除非用户代码可能在某个地方保存指向它们的指针。此行为对于整数类型最为可见。在典型的32位系统上,给定代码:

    uint16_t foo(void);
    uint16_t bar(void);
    uint16_t blah(uint32_t q)
    {
      uint16_t a;
      if (q & 1) a=foo();
      if (q & 2) a=bar();
      return a;
    }
    unsigned short test(void)
    {
      return blah(65540);
    }
    

    test 即使该值不在 uint16_t uint16_t 持有不确定值,不要求读取该值时产生的值在 uint16_t