C++ 未定义的行为:代码检查清单

C++ 未定义的行为:代码检查清单,c++,undefined-behavior,C++,Undefined Behavior,可能重复: 我准备为C++和同级代码审查准备一个清单或指南,因为有太多的场景可能导致可怕的代码>未定义行为,我在想一个在大多数使用的C++语言构造中出现的未定义行为的检查表。p> 当然,不可能预测通过修改序列点之间的变量而产生的未定义行为,但我认为可以列出从其他场景中产生的场景 如果您正在执行代码复查,您会注意哪些通常未定义的行为生成场景?只删除新的指针。例如,您不能调用p=newint[5]然后删除p+2这可能会导致未定义的行为 另外,在尝试使用DLL时,只使用基元类型,因为不同的编译器创建

可能重复:

<>我准备为C++和同级代码审查准备一个清单或指南,因为有太多的场景可能导致可怕的<>代码>未定义行为<代码>,我在想一个在大多数使用的C++语言构造中出现的未定义行为的检查表。p> 当然,不可能预测通过修改序列点之间的变量而产生的未定义行为,但我认为可以列出从其他场景中产生的场景


如果您正在执行代码复查,您会注意哪些通常未定义的行为生成场景?

只删除新的指针。例如,您不能调用
p=newint[5]然后
删除p+2这可能会导致未定义的行为

另外,在尝试使用DLL时,只使用基元类型,因为不同的编译器创建不同的内存布局,如果尝试交换类或结构,可能会导致一些问题

我能想到的另一件事是注意被删除的内存,在某些情况下,您可以从这些位置进行写入和读取,而不会出现任何错误或访问冲突,但这始终是未定义的行为。

(1)
删除

T* p = new T[N];
delete p; // ...1
delete (p+x); //...2
(2)缺少
返回

int* foo ()
{
  // code
  return p;
  // code
}
(3)Double
delete

T* p = new T[N];
delete p; // ...1
delete (p+x); //...2
(4)临时

(5)
向量
元素添加到自身(定义大小时)

向量vi(1); vi.推回(0); vi.向后推(vi[0]);//它可以成为pt(4)的一个用例(有时)
多态基类中的虚拟析构函数不可用

小例子

class Base
{
   public:
    Base();
   // some virtual functions     
   // no virtual destructor
   ~Base();
};

class Derived : public Base
{
   public:
   Derived();
   // override the functions here      
   ~Derived();
};
// definitions
int main()
{
   Base *p = new Derived();
   // function calls
   delete p; // UB
}


是C++中未定义行为场景的综合列表。

< P>比其他答案不明显的情况:

  • 不同转换单元中非局部静态的初始化顺序未定义。即:
a、 cpp

b、 cpp


这是一个半小时的工作,搜索所有提及未定义行为的标准,并列出潜在原因。。。(我的一个旧S.O.答案中包含了这样一个列表)。如果你是认真的,你会想要这样一份详尽的清单,而不是从《S.O.读者》杂志的头版收藏中特别挑选出来的。有了这样一个列表,你就比我们更能说明,考虑到你的编码环境、技术和健壮性需求,你认为哪些值得检查……@Tony:我找不到任何重复项,尽管我明确地搜索过。你能发一个链接到你以前的答案吗?我找不到我的(可能问题在S.O.客房部),但格雷格的链接看起来很准确。@Tony,@Greg Hwegill:谢谢!投票结束这一次。这不一定是UB;它会造成不良影响@艾米琳:绝对是UB$5.3.5/3在第一种选择(删除对象)中,如果操作数的静态类型与其动态类型不同,则静态类型应为操作数的动态类型的基类,并且静态类型应具有虚拟析构函数或行为未定义。@iammilind:Stroustrup教授有一个很好(显然令人困惑)的低调的表达方式,但他的回答与Prason引用的标准一致。是的,标准应该是正确的选择。Bjarne确实低估了它的影响。还要注意的是,如果你使用shared_ptr(你可能应该这样做),你甚至不需要虚拟析构函数来进行多态性使用。你甚至不能
delete p在这种情况下。您必须
删除[]p或它是未定义的行为。@弗雷德·拉森这取决于编译器,在某些编译器中,
delete p
delete[]p
未定义行为的惊人之处之一是,在某些编译器/环境下,它可能看起来定义得很好。@dennis:同意,但遗憾的是,即使在同一个编译器上,如果您只是在其他类的其他文件中添加了与您的错误代码完全无关的内容,那么您的代码也可能无法工作!
struct SomeStatic
{
    SomeStatic()
    {
        // Some init code
    }
    void AMethodUsingTheInitdCode()
    {
        //Blah blah
    }
} static;
struct SomeStatic;
extern SomeStatic static;

struct SomeOtherStatic
{
    SomeOtherStatic()
    {
        static.AMethodUsingTheInitdCode(); //Undefined -- SomeStatic's init code may not have run yet.
    }
} runMe;