【问题标题】:Uninitialized memory in C++Builder / DelphiC ++ Builder / Delphi中未初始化的内存
【发布时间】:2010-10-31 21:04:37
【问题描述】:

Delphi 中的未初始化变量是否保证具有任何特定值

  • 在堆栈上?
  • 在堆上?

由于 C++Builder 通常遵循 Delphi 的设计,因此 C++Builder 中的未初始化变量保证具有任何特定值

  • 在堆栈上?
  • 在堆上,对于派生自 TObject 的类的成员变量?
  • 在堆上,对于POCOs的成员变量?

我继承了一些 C++Builder 代码,这些代码在很大程度上依赖于零初始化的成员变量,我正在尝试弄清楚该语言是否能保证这一点。

Windows 是否保证在第一次将内存分配给程序的堆栈或堆时对其进行零初始化? (编辑:我意识到程序在执行时会覆盖内存,因此它不能继续依赖于此;我只是想弄清楚我观察到的行为。)

【问题讨论】:

    标签: delphi c++builder initialization


    【解决方案1】:

    由于 caskey 的回答只涉及 c++ 我对 delphi 的回答:

    在delphi中通过Giacomo Degli Esposti引用this answer

    • 对象字段始终初始化为 0、0.0、''、False、nil 或任何适用的值。
    • 始终初始化全局变量。 (到 0)
    • 局部变量是未初始化的,因此您必须先分配一个值才能使用它们。

    ms-help://borland.bds4/bds4ref/html/Variables.htm

    所有致谢Giacomo Degli Esposti

    编辑:“Windows 是否保证在第一次将内存分配给程序的堆栈或堆时将其初始化为零?”

    Windows 保证在首次将内存分配给新进程时将其初始化为零(否则,您将遇到一个很大的安全问题,即程序能够读取其他进程丢弃的内存而不管权限如何)。然而,使用 c++ 这个保证对你没有多大帮助,因为 c-runtime 可以在你的代码有机会使用它之前自行决定覆盖内存。

    Edit2:对于 c++ 构建器变量显然是为“VCL-style classes”初始化的(无论如何,所有这些都继承自 TObject?),请参阅 http://docs.embarcadero.com/products/rad_studio/cbuilder6/EN/CB6_DevelopersGuide_EN.pdf

    我引用:

    “因为数据成员可能在虚函数中使用,重要的是 了解它们何时以及如何被初始化。在 Object Pascal 中,所有未初始化的数据 是零初始化的。例如,这适用于其构造函数为 不调用继承。 在标准 C++ 中,不能保证 未初始化的数据成员。以下类型的类数据成员必须是 在类的构造函数的初始化列表中初始化: • 参考 • 没有默认构造函数的数据成员

    尽管如此,这些数据成员的值,或那些在 构造函数,在调用基类构造函数时未定义。 在 C++Builder 中, VCL 风格类的内存是零初始化的。

    从技术上讲,它是 VCL 或 CLX 类的内存为零,即位是 零,这些值实际上是未定义的。例如,引用为零。

    一个依赖于在 构造函数的主体或初始化列表中的变量可能表现为 初始化为零。这是因为基类构造函数在 处理初始化列表或进入构造函数体。

    #include <sysutils.hpp>
    class Base : public TObject {
    public:
        __fastcall Base() { init(); }
            virtual void __fastcall init() { }
        };
    class Derived : public Base {
        public:
            Derived(int nz) : not_zero(nz) { }
            virtual void __fastcall init()
            {
            if (not_zero == 0)
            throw Exception("not_zero is zero!");
            }
        private:
            int not_zero;
    };
    int main(void)
    {
        Derived *d42 = new Derived(42);
        return 0;
    }
    

    本例在 Base 的构造函数中抛出异常。因为基地是 在 Derived 之前构造的 not_zero 尚未初始化为 42 的值 传递给构造函数。请注意,您无法初始化您的数据成员 在调用其基类构造函数之前的 VCL 样式类。”

    【讨论】:

    • 不应该是“谨慎”而不是“离题”吗?
    【解决方案2】:

    简答:在 C++ 中,您必须初始化所有内容

    如果 C++Builder 与 C++ 类似,那么除非您明确初始化它,否则不能保证内存的内容。

    虽然窗口在程序的堆栈或堆可用之前可能会出现空白页,但除非您从操作系统请求自己的内存,否则您可能正在使用构造函数或库来分配内存。更多时候,您会获得自己已经使用过的页面或内存区域。在这种情况下,它几乎可以保证是脏的。对于几乎从来不是新页面的堆栈页面来说更是如此。

    memset() 将是您在 C 中擦除内存的方式,但在 C++ 中,您需要为每个字段提供默认值,或者在构造函数中显式初始化它们。

    【讨论】:

    • 我知道 C++ 是这样工作的,但是 C++Builder 有时会遵循 Delphi 模型而不是 C++ 模型。我在这里处理大量遗留代码,如果语言保证初始化,那么有比自己初始化所有内容更高优先级的任务。
    • 那么C++Builder在什么情况下遵循Delphi模型呢? C++就是C++。零初始化的唯一区别是您是否从 Delphi 类(如 TForm)继承。那是因为 System::TObject::InitInstance() 方法用零填充内存。
    • @Andreas:在处理 TForm 子类等 VCL 样式类时,C++Builder 遵循 Delphi 模型。请参阅audacia-software.de/en/bcb/delphi-and-cpp-classes.htm(如果我在发布之前足够仔细地阅读它,它会回答我的问题)。
    • 遵循“Delphi模型”完全符合C++。 C++ 不禁止默认初始化。它是未定义的。因此,任何特定的实现(例如 C++ Builder)都可以初始化变量并且仍然符合标准。允许实现加强标准的“未定义”和“实现定义”部分以使其定义。
    • @Rob:很好,尽管 C++Builder 也遵循 Delphi 模型,但与 C++ 不一致(构造函数的顺序、异常处理细节等;请参阅链接 I提供更多详细信息)。
    【解决方案3】:

    在C++内存保证在以下情况下被初始化:

    • 用于静态分配的变量
    • 对于具有初始化其成员的构造函数的对象

    在第一种情况下,整数、指针等 POD 数据类型将被初始化为零。

    这些是 C++ 标准提供的唯一保证。 Windows 在这方面根本不提供任何保证。

    【讨论】:

      【解决方案4】:

      在 Delphi 中,TObject 构造函数将对象的堆分配(总是在堆上,因为 TObjects 不能在 Delphi 中进行堆栈实例化)内存初始化为零,从而清除所有成员变量。

      【讨论】:

        【解决方案5】:

        据我所知,在 Delphi 上: * vcl 类自动初始化其字段。 * 全局变量

        局部变量没有初始化。它们的初始内容是完全未定义的。因此,如果 variable 是本地的,则 TObject 类型的 Assigned(variable) 将始终返回 false。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-13
          • 2015-12-25
          • 1970-01-01
          • 2020-07-28
          • 2011-07-01
          • 1970-01-01
          相关资源
          最近更新 更多