2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DelphiでGetMemやAllocMemの代わりに動的配列のSetLengthを使って、スマートポインタを実現する

Last updated at Posted at 2025-08-09

サンプル1

可変長配列付き構造体で領域を動的に確保する例

PBitmapInfo = ^TBitmapInfo;
TBitmapInfo = record
  bmiHeader: TBitmapInfoHeader;
  bmiColors: array[0..0] of TRGBQuad;
end;

GetMemを使ったコード

コードを見る
procedure Example;
var
  bmpInfo: PBitmapInfo;
  size, i: Integer;
begin
  // パレット256色分のサイズを計算
  size := SizeOf(TBitmapInfoHeader) + SizeOf(TRGBQuad) * (256 - 1);

  // 領域確保
  GetMem(bmpInfo, size);

  try
    FillChar(bmpInfo^, size, 0);

    // ヘッダー設定
    with bmpInfo.bmiHeader do
    begin
      biSize := SizeOf(TBitmapInfoHeader);
      biWidth := 100;
      biHeight := 100;
      biPlanes := 1;
      biBitCount := 8;
      biCompression := BI_RGB;
    end;

    // パレット設定(ここではグレースケール)
{$R-}
    for i := 0 to 255 do
    begin
      bmpInfo.bmiColors[i].rgbRed := i;
      bmpInfo.bmiColors[i].rgbGreen := i;
      bmpInfo.bmiColors[i].rgbBlue := i;
      bmpInfo.bmiColors[i].rgbReserved := 0;
    end;
{$R+}

    // bmpInfoを使っていろいろ処理

  finally
    FreeMem(bmpInfo);
  end;
end;

動的配列を使ったコードではこうなります

procedure Example;
var
  bmpInfo: PBitmapInfo;
  buffer: TBytes;
  size, i: Integer;
begin
  // パレット256色分のサイズを計算
  size := SizeOf(TBitmapInfoHeader) + SizeOf(TRGBQuad) * (256 - 1);

  // 領域確保
// GetMem(bmpInfo, size);
  SetLength(buffer, size);

  // 先頭アドレスをbmpInfoにセット
  bmpInfo := @buffer[0];

  // ヘッダー設定
  with bmpInfo.bmiHeader do
  begin
    ... 上と同じ
  end;

  // パレット設定(ここではグレースケール)
{$R-}
  for i := 0 to 255 do
  begin
    ... 上と同じ
  end;
{$R+}

  // bmpInfoを使っていろいろ処理

  // 開放処理が不要
end;

GetMem(bmpInfo, size);
FillChar(bmpInfo^, size, 0);
FreeMem(bmpInfo);

SetLength(buffer, size);
bmpInfo := @buffer[0];
に置き換えます

メリット

  • 開放が不要になる
  • 0クリアが不要になる(SetLengthは中身が初期化されるため)

デメリット

  • 余計な変数の宣言が必要 buffer: TBytes;
  • 余計な代入が発生 bmpInfo := @buffer[0];
  • 知らない人が見ると??となるかも

サンプル2

GDI+を使って画像データのPixelデータを配列で取得

uses
  GDIPAPI, GDIPOBJ;

procedure GetPixels(Bitmap: TGPBitmap);
var
  Pixels: TArray<ARGB>;
  Width, Height: Integer;
  BitmapData: TBitmapData;
begin
  Width := Bitmap.GetWidth;
  Height := Bitmap.GetHeight;
  SetLength(Pixels, Width * Height);

  Bitmap.LockBits(MakeRect(0, 0, Width, Height), ImageLockModeRead, PixelFormat32bppARGB, BitmapData);
  try
    // ピクセルデータを読み込み
    Move(BitmapData.Scan0^, Pixels[0], Width * Height * SizeOf(ARGB));
  finally
    Bitmap.UnlockBits(BitmapData);
  end;

  // Pixelsを使っていろいろ処理
end;

procedure Example;
var
  Bitmap: TGPBitmap;
begin
  Bitmap := TGPBitmap.Create('sample.png');
  GetPixels(Bitmap);
  Bitmap.Free;
end;

以下の個所が今回の肝となる個所です
SetLength(Pixels, Width * Height);
Move(BitmapData.Scan0^, Pixels[0], Width * Height * SizeOf(ARGB));

メリット

  • メモリの確保と開放が不要
  • 面倒なポインタアクセスが不要
  • バイト単位ではなく1Pixel(ドット)単位でロジックが記述できるようになる

デメリット

  • 特に思いつかない

GDI+に興味がある方は過去の記事を参照ください

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?