是否有没有未定义行为的安全版本的 C++?

Som*_*mer 3 c++ undefined-behavior

C++ 中的未定义行为真的很难调试。是否有一个版本的 C++ 和标准库不包含任何未定义的行为而是抛出异常?我知道这将是一个性能杀手,但我只打算在我在调试模式下编程、调试和编译时使用这个版本,并不真正关心性能。理想情况下,此版本是可移植的,您可以轻松打开/关闭未定义的行为检查。

例如,你可以实现一个像这样的安全指针类(只检查空指针,实际上如果它指向一个有效的内存块,则不会):

template <typename T>
class MySafePointer {
     T* value;
public:
      auto operator-> () {
          #ifndef DEBUG_MODE
          assert(value && "Trying to dereference a null pointer");          
          #endif
          return value;
      }
      /* Other Stuff*/

};
Run Code Online (Sandbox Code Playgroud)

在这里,用户只需要#undef DEBUG_MODE在您想恢复性能时才需要。

是否有 C++ 的库/安全版本可以做到这一点?

编辑:更改了上面的代码,使其实际上更有意义并且不会抛出异常但断言值非空。问题只是一个描述性错误消息与崩溃的问题......

Joh*_*nck 5

是否有一个版本的 C++ 和标准库不包含任何未定义的行为而是抛出异常?

不,那里没有。正如评论中提到的,有 Address Sanitizer 和 Undefined Behavior Sanitizer 以及许多其他可以用来寻找错误的工具,但没有“没有未定义行为的 C++”实现。

如果您想要一种本质安全的语言,请选择一种。C++ 不是。

  • @SomeProgrammer - C++ 标准明确定义了“未定义”的含义,并且(在可以的情况下)指定了行为未定义的位置。Java 规范没有这样做,但仍然有(大部分被忽略)未定义行为的示例。Java 设计者试图消除 C++ 中未定义的行为(通过定义特定结果或阻止它们发生),而不记录这样做的权衡(例如,在某些机器上而不是在其他机器上的运行时成本,对某些程序员来说是直观的,但对某些程序员来说却是不直观的)其他的)。Java 的标签是“一次编写,到处调试”是有原因的。 (3认同)
  • @SomeProgrammer,我相信这对许多(如果不是大多数)语言来说都是一种耻辱。 (2认同)
  • @SomeProgrammer,本质上不安全的语言。你认识一个吗?顺便说一句,任何未在其标准中定义某些内容的语言都承认未定义的行为。所以你实际上是在问是否有一种语言的标准定义了所有可能的场景。你知道其中之一吗? (2认同)

Enr*_*lis 3

未定义的行为

\n

未定义的行为意味着您的程序最终处于标准未定义其行为的状态。\xc2\xb9

\n

所以你真正要问的是是否有一种语言的标准定义了所有可能的场景。

\n

我想不出一种这样的语言,原因很简单,程序是由机器运行的,而编程语言和标准是由人类编写的。

\n

总是无心的吗?

\n

根据上述原因,该标准可能存在无意的“漏洞”,即未有意允许的未定义行为,甚至可能在标准化过程中没有注意到。

\n

然而,正如标准中所有“未定义行为”句子所证明的那样,很多时候 UB 是被有意允许的。

\n

但为什么?因为这意味着给程序员提供更少的保证,而好处是能够进行更多优化,或者等效地,不浪费时间验证用户是否遵守定义的合同。

\n

因此,即使标准没有漏洞,标准中仍然会出现很多情况,因为编译器可以利用它来进行各种优化。\xc2\xb2

\n

在一些微不足道的情况下预防它的影响

\n

std::vector未定义行为的一个小例子是当您访问via的越界元素时operator[]。与 C 风格数组完全相同,v[i]基本上返回*(v_ + i)v_包装到 中的指针在哪里v。这很快但不安全。\xc2\xb3

\n

如果你想i安全地访问第 th 元素怎么办?您将不得不更改的实现std::vector<>::operator[]

\n

那么支持国旗会产生什么影响呢DEBUG_MODE?本质上,您必须编写两个实现,并用#ifdef/( #else/)分隔#endif。显然,这两种实现有很多共同点,因此您可以#在代码中进行多次分支。但是......是的,我的底线是可以通过改变标准来满足您的要求,从而迫使实施者为所有事情支持两种不同的实现(安全和快速/不安全和慢速)。

\n

顺便说一句,对于这种特定情况,标准确实定义了另一个函数 ,at它需要处理越界情况。但这就是重点:它是另一个函数。

\n
\n

(\xc2\xb9) 在这种情况下标准(我的重点

\n
\n

对使用该输入执行该程序的实现没有任何要求(甚至对于第一个未定义操作之前的操作也没有要求

\n
\n

(\xc2\xb2) 我真的建议阅读Nicol Bolas这个关于 s 中缺少 UB 的答案。constexpr

\n

(\xc2\xb3)这篇优秀的文章中列出了 UB 的这个例子和其他例子;搜索Out of Bounds以获取我制作的示例。

\n

  • 核心转储是最具描述性的错误消息。它显示了崩溃时程序状态的每个细节!当您尝试修复错误时,什么会更有帮助? (2认同)