クラスのオブジェクトがどこに割り当てられているかを知ることができるメカニズムを作ろうとしています。クラスでフラグを作成することを考えましたが、「new」演算子の呼び出し中にオブジェクトの有効期間が開始されないため、値を設定できません。C ++で、オブジェクトがスタックまたはヒープ(ランタイム)にあるかどうかを判断することは可能ですか?
2 に答える
これを実行するための移植可能な方法はありませんが、これを実行するシステムの種類が限られている場合は、次の方法を試すことができます。
メインのローカル変数のアドレスを取得します(または他の「コールスタックの下位」)。これをグローバル変数に保存して、呼び出しましょうchar *stackbase;
次に、チェックインしている関数内のローカル変数のアドレスを取得し、それを呼び出しましょうchar *stacktop;
ここで、 がある場合、次のようchar *obj = reinterpret_cast<char *>(object_in_test);
になります。
if (obj > stacktop && obj < stackbase) on_stack = true;
else on_stack = false;
これにはいくつかの欠陥があることに注意してください。
- これは技術的に未定義の動作です。メモリ空間全体が連続しているため、ほとんどのシステムで動作します。しかし、スタックとメモリの他のセクションが別々の「アドレス空間」を持つシステムがあります。つまり、異なるタイプのメモリへの 2 つのポインタが同じアドレスを持つことができます。
- スレッドには、「スレッドごとのスタックベース」が必要です。
- スタックは「ゼロに向かって成長する」と想定されます (そうでない場合は、if で
>
andを反転する必要があります<
。 - グローバル変数は として表示され
not on stack
ます。 - 自己責任!
以下の免責事項にもかかわらず、言語弁護士によって反対票が投じられるため、この回答を削除する必要があると私は完全に予想しています.
私はいくつかの実験を行っており、オブジェクトがスタックに割り当てられているかどうかを実行時に常に通知できるようにするために、これが機能しているように見えることを発見しました。
インターフェイスは次のとおりです。
#ifndef HEAPAWARE_H
#define HEAPAWARE_H
#include <cintttypes>
class HeapAware
{
public:
HeapAware();
void *operator new(std::size_t size);
void *operator new[](std::size_t size);
void operator delete(void *ptr, std::size_t);
void operator delete[](void *ptr, std::size_t);
bool is_on_heap() const { return on_heap; }
std::ptrdiff_t get_heap_array_index() const { return heap_array_index; }
private:
const bool on_heap;
const std::ptrdiff_t heap_array_index;
static thread_local HeapAware * last_alloc;
static thread_local std::size_t allocated_size;
};
#endif
そして実装は次のとおりです。
void *HeapAware::operator new(std::size_t size)
{
auto result = last_alloc = reinterpret_cast<HeapAware*>(malloc(size));
allocated_size = 1;
return result;
}
void *HeapAware::operator new[](std::size_t size)
{
auto result = last_alloc = reinterpret_cast<HeapAware*>(malloc(size));
allocated_size = size;
return result;
}
void HeapAware::operator delete(void *ptr, std::size_t)
{
free(ptr);
}
void HeapAware::operator delete[](void *ptr, std::size_t)
{
free(ptr);
}
HeapAware::HeapAware():on_heap(this>=last_alloc && this<last_alloc+allocated_size),heap_array_index(allocated_size>1?this-last_alloc:-1)
{
}
thread_local HeapAware * HeapAware::last_alloc = nullptr;
thread_local std::size_t HeapAware::allocated_size = 0;
これは常に正しく動作するようです。ヒープに割り当てられた配列の場合、エントリのインデックスも利用できます。スタックに割り当てられた値、または単独で割り当てられたエントリの場合、get_heap_array_index()
関数は -1 を返します。
このコードは、特定のスレッドでの構築の直前に new 演算子が呼び出されることを前提としています。ただし、この仮定は、私が試したすべてのものに当てはまるようです。