MGL::Memory::Allocator#

概要#

MGL::Memory::AllocatorはMGL用のメモリアロケータを実装するためのインターフェースクラスです。このインターフェースを継承したクラスを用いることで、MGLが使用するアロケータを任意のものに変更可能となります。

独自アロケータの実装についてはメモリアロケータの作成(準備中)を参照してください。

宣言#

namespace MGL::Memory
{
    class Allocator;
}

メンバ情報#

種類

名前

内容

純粋仮想関数

GetType

このアロケータを表す値の取得

純粋仮想関数

Initialize

初期化処理

純粋仮想関数

IsInitialized

初期化状態の取得

純粋仮想関数

Allocate

メモリの確保

純粋仮想関数

Deallocate

メモリの解放

純粋仮想関数

GetSizeInfo

サイズ情報を取得


GetType#

このアロケータを表す値の取得

宣言#

namespace MGL::Memory
{
    class Allocator
    {
        virtual AllocatorType GetType() const noexcept = 0;
    };
}

戻り値#

MGL::Memory::AllocatorType

このアロケータを表す値

説明#

外部からこのアロケータを判別する際に使用する値を取得します。この関数はMGL::Memory::GetAllocatorTypeが使用中のアロケータに対して呼び出しを行います。

この関数の戻り値にはMGL::Memory::MakeAllocatorTypeに任意の文字列を与えて生成した値を返してください。

利用例#

class YourAllocator : public MGL::Memory::Allocator
{
public:
    // このアロケータを表す値を生成。
    // publicな定数にしておくと判別の際に利用しやすい。
    static constexpr auto kAllocatorType = MGL::Memory::MakeAllocatorType("YourAllocatorName");

    // このアロケータを表す値を取得
    virtual AllocatorType GetType() const noexcept override
    {
        return kAllocatorType;
    }

    ... // その他の実装
};

関連#


Initialize#

初期化処理

宣言#

namespace MGL::Memory
{
    class Allocator
    {
        virtual bool Initialize() noexcept = 0;
    };
}

戻り値#

bool

成功時にtrue、失敗時にfalse

説明#

アロケータの初期化を行う関数です。

この関数はMGL::Memory::SetAllocatorが呼び出された際に、IsInitializedfalseを返す場合に自動で呼び出されます。手動で呼び出したい場合は、この関数を呼び出した後にIsInitializedtrueを返すように実装してください。

MGL::Memory::SetAllocatorがこの関数を呼び出してfalseが返された場合、アロケータの登録は行われません。

利用例#

// 初期化まわりの実装例

class YourAllocator : public MGL::Memory::Allocator
{
public:
    // コンストラクタで初期化済みフラグをfalseに設定
    constexpr YourAllocator() noexcept
        : _isInitialized(false)
    {
    }

    // 初期化処理
    virtual bool Initialize() noexcept override
    {
        ... // 初期化処理

        _isInitialized = true;
    }

    // 初期化状態を取得
    virtual bool IsInitialized() const noexcept override
    {
        return _isInitialized;
    }

    ... // その他の実装

private:
    bool _isInitialized;    // 初期化フラグ
};

呼び出し側の例についてはMGL::Memory::SetAllocatorを参照してください。

関連#


IsInitialized#

初期化状態の取得

宣言#

namespace MGL::Memory
{
    class Allocator
    {
        virtual bool IsInitialized() const noexcept = 0;
    };
}

戻り値#

bool

初期化済みまたは初期化不要の場合はtrue、初期化が必要な場合はfalse

説明#

アロケータの初期化状態を返す関数です。アロケータが初期化済み、または初期化の必要がない場合はtrueを返してください。

この関数がfalseを返すアロケータをMGL::Memory::SetAllocatorに指定した場合、内部でInitializeを呼び出して初期化を試みます。初期化に失敗した場合はアロケータの登録は行われません。

利用例#

初期化処理も含めてInitializeを参照してください。

関連#


Allocate#

メモリの確保

宣言#

namespace MGL::Memory
{
    class Allocator
    {
        [[nodiscard]] virtual void *Allocate(size_t size) noexcept = 0;
    };
}

引数#

size_t size

要求サイズ

戻り値#

void *

確保したバッファの先頭アドレス。失敗時にはnullptr

説明#

このアロケータを用いてメモリの確保を行う際に呼び出される関数です。この関数はMGL::Memory::Allocateによって呼び出されます。

引数で指定されたサイズを満たす利用可能なバッファを準備し、その先頭アドレスを返してください。メモリの確保に失敗した場合はnullptrを返してください。

この関数は異なる複数のスレッドから同時に呼び出される可能性があるため、マルチスレッドセーフな実装である必要があります。

注釈

MGLはメモリの確保に失敗した場合のプログラムの継続を保証していません。MGL::STL名前空間以下のクラスまたは関数においてはstd::bad_allocをスローしますが、それ以外の多くの状況ではstd::terminate()によってプログラムを異常終了させます。ゲームプログラミングにおいては、メモリの確保に失敗する状況を作らないことを優先してください。

利用例#

アロケータの実装依存につき省略します。呼び出し側の利用例についてはMGL::Memory::Allocateを参照してください。

関連#


Deallocate#

メモリの解放

宣言#

namespace MGL::Memory
{
    class Allocator
    {
        virtual void Deallocate(void *buffer) noexcept = 0;
    };
}

引数#

void *buffer

解放するバッファのアドレス

説明#

このアロケータによって確保されたバッファを解放する際に呼び出される関数です。この関数はMGL::Memory::Deallocateによって呼び出されます。

引数で受けたアドレスをアロケータへと返却する処理を実装してください。

この関数は異なる複数のスレッドから同時に呼び出される可能性があるため、マルチスレッドセーフな実装である必要があります。

注釈

Cのfree()およびC++のdeleteはNULLポインタを受けた際に何も行わない事が規定されていますが、その処理はこの関数の呼び出し元で行われているため、この関数内部でNULLチェックを行う必要はありません。

利用例#

アロケータの実装依存につき省略します。呼び出し側の利用例についてはMGL::Memory::Allocateを参照してください。

関連#


GetSizeInfo#

サイズ情報を取得

宣言#

namespace MGL::Memory
{
    class Allocator
    {
        virtual bool GetSizeInfo(size_t &dest, uint32_t key, uint32_t arg) noexcept = 0;
    };
}

引数#

size_t &dest

取得したサイズ情報の格納先

uint32_t key

取得するサイズの種類を表すキー

uint32_t arg

取得の際に使用する引数

戻り値#

bool

成功時にtrue、失敗時にfalse

説明#

このアロケータのサイズ情報を取得する際に呼び出される関数です。この関数はMGL::Memory::GetSizeInfoによって呼び出されます。

この関数は主にメモリの使用状況をモニタリングする際に利用します。アプリケーション側でモニタリングする必要が無い場合はこの関数の実装は不要ですので、単にfalseを返すだけで問題ありません。

アロケータがどのようなサイズを扱うかは実装するアルゴリズムに依存するため、MGL側では明確な定義を行っていません。多くの場合、確保可能な最大容量や確保済みの総容量、確保しているバッファの数などがアプリケーション側にとって有用な情報となります。引数のkeyがどの種類の情報を表し、argがどのように扱われるかについてはアロケータ側で定義してください。

情報が正しく取得できた場合、destにその結果を書き込みtrueを返してください。keyに対応する情報が存在しない場合など、情報が取得できなかった場合はfalseを返してください。

利用例#

// 確保済みのサイズ、確保数、確保可能な最大サイズを返す例

class YourAllocator : public MGL::Memory::Allocator
{
public:
    // サイズ情報に対応するキーの定義
    enum
    {
        kSizeKey_UsedSize,              // 確保済みのサイズを表すキー
        kSizeKey_UsedCount,             // 確保数を表すキー
        kSizeKey_MaxAllocatableSize,    // 確保可能な最大サイズを表すキー
    };

    // サイズ情報を取得
    virtual bool GetSizeInfo(size_t &dest, uint32_t key, uint32_t arg) noexcept override
    {
        // サイズ情報は異なるスレッドによって書き換えられる可能性があるため、
        // 取得の際にも同期を取らないと正しい値が得られない場合がある。
        std::lock_guard lock(_mutex);

        switch (key)
        {
            // 確保済みのサイズ
            case kSizeKey_UsedSize:
                dest = _usedSize;
                return true;

            // 確保数
            case kSizeKey_UsedCount:
                dest = _usedCount;
                return true;

            // 確保可能な最大サイズ
            case kSizeKey_MaxAllocatableSize:
                dest = _maxAllocatableSize;
                return true;

            default:
                break;
        }

        // 上記に該当しないキーを受けた場合はfalseを返す
        return false;
    }

    ... // その他の実装

private:
    // 各種サイズ情報
    // これらの変数は Allocate() / Deallocate() によって変動するものとする
    size_t _usedSize;               // 確保済みのサイズ
    size_t _usedCount;              // 確保数
    size_t _maxAllocatableSize;     // 確保可能な最大サイズ

    // 同期用のmutex
    // このmutexは Allocate() / Deallocate() でも使用すると想定
    std::mutex _mutex;
};

関連#