newした配列のサイズ

newした配列は最後にdelete[]を使って解放するわけですが、「何個解放するか」は誰が知ってるのか。
コンパイラによって異なると思いますが、GCC 4.6では先頭要素の1つ前にサイズが入ってました。

#include <iostream>

struct X {
    X()
    {
        std::cout << "ctor" << std::endl;
    }

    ~X()
    {
        std::cout << "dtor" << std::endl;
    }
};

int main()
{
    const std::size_t n = 3;
    X* xs = new X[n];

    std::cout << *(reinterpret_cast<std::size_t*>(xs) - 1) << std::endl;

    delete[] xs;
}
ctor
ctor
ctor
3
dtor
dtor
dtor

ただし、デストラクタを呼ぶ必要のない型については、サイズがどこにもなかったりします。

#include <iostream>

int main()
{
    const std::size_t n = 3;
    int* xs = new int[n];

    std::cout << *(reinterpret_cast<std::size_t*>(xs) - 1) << std::endl;

    delete[] xs;
}
1442542072972412669

こういうのをうまく使えば、サイズ変数を内部に必要としない可変長配列クラスを作れたりすると思います。


と、こういう話を大阪に行った時に id:melpon から聞いたので試してみました。