オブジェクトをバッファに格納しています。... オブジェクトの全体的なサイズがわかっている場合、このメモリへのポインタを作成して関数を呼び出すことはできますか?
これは、キャストの使用が許容される範囲で許容されます。
#include <iostream>
namespace {
class A {
int i;
int j;
public:
int value()
{
return i + j;
}
};
}
int main()
{
char buffer[] = { 1, 2 };
std::cout << reinterpret_cast<A*>(buffer)->value() << '\n';
}
オブジェクトを raw メモリなどにキャストしてから戻すことは、特に C の世界では、実際にはかなり一般的です。ただし、クラス階層を使用している場合は、メンバー関数へのポインターを使用する方が理にかなっています。
次のクラスがあるとします: ...
このクラスのサイズが 24 であることがわかっていて、メモリ内で開始するアドレスがわかっている場合...
ここが難しいところです。オブジェクトのサイズには、そのデータ メンバー (および任意の基本クラスのデータ メンバー) のサイズに、パディング、関数ポインター、または実装に依存する情報を加えたものから、特定のサイズの最適化 (空の基本クラスの最適化) によって保存されたものを差し引いたものが含まれます。結果の数値が 0 バイトの場合、オブジェクトは少なくとも 1 バイトのメモリを必要とします。これらは、言語の問題と、ほとんどの CPU がメモリ アクセスに関して持つ一般的な要件の組み合わせです。 物事を適切に機能させようとするのは、本当に大変なことです。
オブジェクトを割り当てて生メモリとの間でキャストするだけであれば、これらの問題は無視できます。しかし、オブジェクトの内部を何らかのバッファにコピーすると、オブジェクトはすぐに頭をもたげます。上記のコードは、アラインメントに関するいくつかの一般的なルールに依存しています (つまり、クラス A には int と同じアラインメント制限があるため、配列を安全に A にキャストできることをたまたま知っていますが、必ずしも配列の一部を A にキャストし、一部を他のデータ メンバーを持つ他のクラスにキャストした場合も同様です)。
ああ、オブジェクトをコピーするときは、ポインタを適切に処理していることを確認する必要があります。
Google の Protocol BuffersやFacebook の Thriftなどにも興味があるかもしれません。
はい、これらの問題は難しいです。そして、はい、一部のプログラミング言語はそれらを覆い隠しています。 しかし、敷物の下に一掃されているものは非常にたくさんあります。
Sun の HotSpot JVM では、オブジェクト ストレージは最も近い 64 ビット境界に合わせられます。これに加えて、すべてのオブジェクトにはメモリ内に 2 ワードのヘッダーがあります。JVM のワード サイズは通常、プラットフォームのネイティブ ポインター サイズです。(32 ビットの int と 64 ビットの double だけで構成されるオブジェクト -- 96 ビットのデータ -- が必要です) オブジェクト ヘッダーに 2 ワード、int に 1 ワード、double に 2 ワード。それは 5 ワードで、160 ビットです。アラインメントのため、このオブジェクトは 192 ビットのメモリを占有します。
これは、Sun がメモリ アラインメントの問題に対して比較的単純な戦術に依存しているためです (架空のプロセッサでは、char は任意のメモリ位置に存在でき、int は 4 で割り切れる任意の位置に存在でき、double は必要になる場合があります)。は 32 で割り切れるメモリ位置にのみ割り当てられますが、最も制限の厳しい位置合わせ要件は他のすべての位置合わせ要件も満たしているため、Sun は最も制限の厳しい位置に従ってすべてを位置合わせしています)。
メモリ アラインメントの別の戦術では、そのスペースの一部を再利用できます。