如何在不分配内存的情况下构造对象?

时间:2017-06-01 05:30:35

标签: delphi

我希望其他对象中包含的对象不必分配内存。例如在Delphi中我可以这样写:

type
  TTest = class
    obj1: tobject1;
    obj2: tobject2;
    constructor Create;
    destructor Destroy; override;
  end;

constructor TTest.Create;
begin
  inherited;
  obj1 := tobject1.Create;
  obj2 := tobject2.Create;
end;

destructor TTest.Destroy;
begin
  obj1.Free;
  obj2.Free;
  inherited;
end;

类似的C ++代码如下所示:

class TTest {
    tobject1 obj1;
    tobject2 obj2;
};

我想关注的区别在于Delphi版本中有3个内存分配,而C ++版本只有1个。有没有办法只在Delphi中为一个完整的对象及其子对象分配一个内存,就像在C ++中一样?

更新:完整的C ++测试代码:

class tobject1 { public: int aaa; };
class tobject2 { public: int bbb; };

class TTest {
    tobject1 obj1;
    tobject2 obj2;
public:
    void doThing() { obj1.aaa = obj2.bbb; };
};

int main()
{
    {TTest * test = new TTest; test->doThing(); delete test; }
    {TTest test; test.doThing(); }

    return 0;
}

反汇编代码:

{TTest * test = new TTest; test->doThing(); delete test; }
013D182E  push        8  
013D1830  call        operator new (013D1299h)  
013D1835  add         esp,4  
013D1838  mov         dword ptr [ebp-0E4h],eax  
013D183E  mov         eax,dword ptr [ebp-0E4h]  
013D1844  mov         dword ptr [ebp-8],eax  
013D1847  mov         ecx,dword ptr [ebp-8]  
013D184A  call        TTest::doThing (013D133Eh)  
013D184F  mov         eax,dword ptr [ebp-8]  
013D1852  mov         dword ptr [ebp-0F0h],eax  
013D1858  push        8  
013D185A  mov         ecx,dword ptr [ebp-0F0h]  
013D1860  push        ecx  
013D1861  call        operator delete (013D104Bh)  
013D1866  add         esp,8  
{TTest test; test.doThing(); }
013D1869  lea         ecx,[ebp-18h]  
013D186C  call        TTest::doThing (013D133Eh)  

对于包含子对象的新对象,c ++对象只需要1个内存分配,如果将对象放在堆栈而不是堆上,则甚至需要0个内存分配。

更新:完整的Delphi测试代码:

program Project1;

type
  tobject1 = class
    aaa: longint;
  end;

  tobject2 = class
    bbb: longint;
  end;

  TTest = class
    obj1: tobject1;
    obj2: tobject2;
    constructor Create;
    destructor Destroy; override;
    procedure doThing;
  end;

constructor TTest.Create;
begin
  inherited;
  obj1 := tobject1.Create;
  obj2 := tobject2.Create;
end;

destructor TTest.Destroy;
begin
  obj1.Free;
  obj2.Free;
  inherited;
end;

procedure TTest.doThing;
begin
  obj1.aaa := obj2.bbb;
end;

var
  test: TTest;

begin
  test := TTest.Create;
  test.doThing;
  test.Free;
end.

反汇编的分配代码:

Project1.dpr.35: test := TTest.Create;
0040A0F4 B201             mov dl,$01
0040A0F6 A19C924000       mov eax,[$0040929c]
0040A0FB E8DCF2FFFF       call TTest.Create
0040A100 A3F8F44000       mov [$0040f4f8],eax
Project1.dpr.36: test.doThing;
0040A105 A1F8F44000       mov eax,[$0040f4f8]
0040A10A E865F3FFFF       call TTest.doThing
Project1.dpr.37: test.Free;
0040A10F A1F8F44000       mov eax,[$0040f4f8]
0040A114 E8DBA1FFFF       call TObject.Free

反汇编的创建代码:

Project1.dpr.16: obj1 := tobject1.Create;
004093F4 B201             mov dl,$01
004093F6 A144914000       mov eax,[$00409144]
004093FB E8C4AEFFFF       call TObject.Create
00409400 8B55FC           mov edx,[ebp-$04]
00409403 894204           mov [edx+$04],eax
Project1.dpr.17: obj2 := tobject2.Create;
00409406 B201             mov dl,$01
00409408 A1F0914000       mov eax,[$004091f0]
0040940D E8B2AEFFFF       call TObject.Create
00409412 8B55FC           mov edx,[ebp-$04]
00409415 894208           mov [edx+$08],eax

此Delphi对象需要3个内存分配,用于包含2个子对象的新对象。是否可以使用对象而不是记录(因为它们不支持继承而完全不相同)来减少像C ++中的一个分配(如果放在堆栈中,甚至是0)(

2 个答案:

答案 0 :(得分:2)

在Delphi中,类是引用类型,因此在实例化时始终会产生堆位置。因此,您无法使用类实现所需的内存布局。

相比之下,记录是价值类型。如果将两个嵌入类型放入记录中,那么内存将按您的意愿布局,并且只有一个堆分配。

答案 1 :(得分:0)

你在这里想错了。 C ++像Delphi一样知道构造函数和析构函数,你只是没有在C ++定义中定义它们。

不,如果不为该实例分配内存,则无法分配类的实例。 Delphi和C ++之间也没有区别。