2

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

  • 在堆栈上?
  • 在堆上?

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

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

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

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

4

5 回答 5

8

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

在德尔福,请参考Giacomo Degli Esposi这个答案

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

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

贾科莫·德格利·埃斯波斯蒂的所有学分

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

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

Edit2:对于 C++ 构建器变量显然是为“ VCL 样式类”初始化的(无论这意味着什么,都是从 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 的构造函数中引发异常。因为 Base 是在 Derived 之前构造的,not_zero 尚未使用传递给构造函数的值 42 进行初始化。请注意,在调用其基类构造函数之前,您不能初始化 VCL 样式类的数据成员。”

于 2009-06-06T14:20:26.893 回答
2

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

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

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

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

于 2009-06-06T14:13:13.540 回答
1

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

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

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

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

于 2009-06-06T14:20:18.813 回答
1

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

于 2009-06-06T14:30:06.687 回答
0

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

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

于 2009-06-12T06:05:11.090 回答