Сыныптағы мүшелердің жалпы типтерінің массивтерін пайдаланып, Weird class данасын өлшеу

Төменде менде кейбір кодта класс құрылымын имитациялайтын кодтың өте қарапайым бөлігі (пішінде тек нұқу оқиғасына бекітілген жалғыз түйме) бар. Мен Delphi XE және XE II-ні қолданамын және бұл класс негізделген өнім кодымдағы объектілерді жойған кездегі жағымсыз апаттарды көріп отырмын. Бұл апаттар тек TMyClass массивінің элементінің мүшелеріне Clear() әдісінде инициализациялауға мүмкіндік берсе ғана пайда болады.

Өкінішке орай, сынақ осы үлгі кодексінде әлі қайталанбайды, бірақ бұл мәселенің себебі болуы мүмкін деп күдіктенетін дана диспетчерлеуімен кейбір өте қызықты мінез-құлыққа ұқсас.

Егер мен үзіліс нүктесін TMyClass.Clear функциясына орналастырсаңыз және 1288 сынып есептерінің InstanceSize мүшесіне қарасаңыз, бұл тек бірдей, себебі тек алаптың мүшесінің өлшемі шынымен 12 кбайт. Мен TRecord2-тен Integer-ге берілетін түрді өзгерте аламын және сол InstanceSize нәтижесін аламын. Егер массивді толығымен сыныптан алып тастасам, мен тек қана бір 128 байт жазу данасын қамтитын сынып үшін жоғарыдан көрінетін ~ 264 байттың Instance өлшемін аламын. Бұл компилятор TMyClass ішіндегі V (TT түрінің) мүшесі үшін жиым қоймасына 1024 байт бөлді.

Мен 12Кб деректерді компилятор өлшемі 1 кб деп есептейтін объектке жазғанда, бізде таңғаларлық дана өлшемі жаман нәрселердің пайда болуына күмәнданамын.

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TRecord = record A : Array[1..128] of byte; end;
  TRecord2 = packed record S : Single; T : TDateTime; end;

  TBase = class(TObject)
    public
      R : TRecord;
  end;

  TBase2 = class(TBase)
    public
      type
        TT = packed array [0..31, 0..31] of T;

      var
        V : TT;
        R2 : TRecord;
  end;

  TMyClass = class(TBase2<trecord2>)
    public
      procedure Clear;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  O : TMyClass;
begin
  O := TMyClass.Create;
  O.Clear;
  O.Free;
end;

{ TMyClass }

procedure TMyClass.Clear;
var
  i, j : integer;
begin
  for i := 0 to 31 do
    for j := 0 to 31 do
      begin
        V[I, J].S := 0;
        V[I, J].T := 0;
      end;
end;

end.
8
+1 Компилятор қатесін таптыңыз!
қосылды автор David Heffernan, көзі
Мәселе туралы біраз жоғалттым, бірақ бұл ақпарат көмектеседі. Clear әдісі бар кіріктірілген сыныптардың көбісі, егер объект жойылып кетсе, Clear әдісі автоматты түрде шақырылады.
қосылды автор Marcus Adams, көзі

1 жауаптар

Бұл минималды ойнату арқылы көрсетілген қате:

program InstanceSizeBug;

{$APPTYPE CONSOLE}

type
  TMyClass = class
    V: array [0..255] of T;
  end;
  TMyClassSingle = class(TMyClass);

begin
  Writeln(TMyClass.InstanceSize);
  Writeln(TMyClassSingle.InstanceSize);
  Readln;
end.

Шығару:

1032
264

Бірдей мінез-құлықты Delphi 2010-да байқауға болатынын ескеріңіз, тек Delphi нұсқасы ғана қолданады.

Отладчик астынан іздеңіз және size Size параметрімен 264 мәніне тең болатындықтан, сіз өзіңізді _GetMem ішінде тапсаңыз, жеткіліксіз жад бөлінеді.

Және, егер бұл күмән туындаса, бұл нұсқасы AV-пен істемейді.

program InstanceSizeBug;

{$APPTYPE CONSOLE}

type
  TMyClass = class
    V: array [1..256*256] of T;
  end;
  TMyClassSingle = class(TMyClass);

begin
  TMyClassSingle.Create.V[256*256] := 0;
end.

Мен бұны Сапа орталығына жібердім # 100561 .

Шешім ретінде сіз конструкторда SetLength арқылы бөлетін динамикалық массаны пайдалануды ұсынамын. Мен компилятордың дұрыс жұмыс істемеуіне мүмкіндік беретін тұрақты өлшемді жиым массасының болуын елестетіп көргім келеді.

8
қосылды
Мен бұл туралы хабарлаймын. QC есептерімен кімнің кімге кіретіні маңызды ма? Бұған қоса, сіз оны ойнату үшін ең қысқа әрі қысқа коды барсыз.
қосылды автор Marjan Venema, көзі
Бұл объектіні жасаудың және бір жолда өріске жазудың ленивый жолы. Мен жад менеджерінің суб-бөлу стратегиясын жою үшін жеткілікті үлкен массив жасау керек болды. Әрине, ол ағып кетеді, бірақ нысанның көлемі тіпті дұрыс емес болғандықтан, мен сіздің құрметті кінәлі емеспін!
қосылды автор David Heffernan, көзі
Мен осы кеште қате туралы QC баяндамасын жіберемін. Мен сіздер үшін айтарлықтай жұмысым жоқ.
қосылды автор David Heffernan, көзі
Дұрыс, енді мен қателіктер жібердім.
қосылды автор David Heffernan, көзі
Мен ұсынылған шешімді енді қосып қойдым.
қосылды автор David Heffernan, көзі
Сәлеметсіз бе, Дэвид, көзге көрінгеніңіз үшін рақмет Ол үшін сапа орталық элементін жасаңыз :-) Осы мәселе бойынша жұмыс бар ма деп ойлайсыз ба? Рахмет, Рэймонд.
қосылды автор Raymond Wilson, көзі
Мен осы сызықпен қызықтырамын: TMyClassSingle.Create.V [256 * 256]: = 0; Бұл синтаксисті бұрын ешқашан көрген емеспін!
қосылды автор Raymond Wilson, көзі
Мен бір жолда жасау және өрістерге қол жеткізуді жақсы көремін және т.с.с. бұл жаңа үлгідегі алапқа бір мәнді тағайындау.
қосылды автор Raymond Wilson, көзі
Динамикалық массив ұсыныстарына рақмет - мен оны беремін.
қосылды автор Raymond Wilson, көзі
Мен жоғарыда ұсынылғандай статикалық массивтің динамикалық нұсқасын пайдаланатын кодты өзгертіп алдым. Коды бұрыннан бастан өткерген жағдайдан бас тартты. :-)
қосылды автор Raymond Wilson, көзі