-1

静的ベース アドレスではなく、動的ベース アドレスを使用してクラスをアドレス指定できるかどうか疑問に思っています。基本的な考え方は次のとおりです。

オブジェクト A を次のように定義します。

class A
{
    //member variables
    ...
    //non-virtual member functions
    ...
    //virtual methods
    virtual void foo(...);
    ...
};

このクラスは、スタック オブジェクトとしてインスタンス化できず、標準の new 演算子がありません。

代わりに、オブジェクトには、ベース アドレスとベース アドレスからメモリへのオフセットを取得し、これを使用して構築用の絶対アドレスを計算する配置 new があります。

私がやりたいことは、次のようにコードでオブジェクトにアクセスすることです:

A* clsA=new(base,offset) A();
...
clsA->foo( ... );

どこ

(char*)clsA == (char*)(base+offset)

さらに、次のことを行うことができます

base+=4;
...
clsA->foo( ... );

そしてまだこれがあります:

(char*)clsA == (char*)(base+offset)

真を保持します。

これが C++ で可能かどうかはわかりません。ASM (x86/amd64) で実行できることは知っていますが、できるだけ多くの移植性を備えたソリューションが必要です (これはまだほとんどないことを認識していますが、何もないよりはましです)。助言がありますか?

編集:だから、私が抱えている問題についてあまり明確ではなかったと思います。アイデアは、動的オブジェクト (ヒープに割り当てられたオブジェクト) をメモリ内で移動できるようにすることです。通常、これは問題にはなりませんが、スタック メモリを介してオブジェクトをインスタンス化できないため、オブジェクトにアクセスする唯一の方法は、オブジェクトの基になるメモリへのポインタを使用することです。配列が移動すると (この例では 4 バイト)、配列から借用されたポインターは無効になり、更新する必要があります。このプロセスは時間がかかるだけでなく、私が望むよりも多くのメモリを消費するため、貸し出された各ポインターのエントリを含む再配置テーブルを格納するのではなく、クラスがアクセス時にメモリ アドレスを再計算できるようにしたいと考えています。

この概念を表すアセンブリは次のとおりです。

;rax stores clsA 
mov rcx, rax 
shr rcx, 32 
mov DWORD PTR[rdx], rax 
lea rax, rdx+rcx 
push rax 
call foo

EDIT 2: 結局のところ、この正確なタイプの動作には MSVC 修飾子もあります。__based は、別のポインターに相対的なポインターを宣言するため、基になるメモリを移動でき、ポインターは有効なままです。記事はこちら

4

3 に答える 3

1

私があなたを理解していれば、必要なのは常に別のポインターに対して相対的なポインターですこれは簡単ですが、通常は悪い考えです。

template<class T>
struct reloc_ptr {
    template<class U>
    reloc_ptr(char*& base, int offset, U&& v) 
        :base(&base), offset(offset) 
    {new(get())T(std::forward<U>(v));}

    T* get() const {return (T*)(*base+offset);}
    T* operator->() const {return get();}
    void destroy() {get()->~T();}
private:
    char** base;
    int offset;
};

そして、通常の使用法は次のようになります

int main() {
    char* base = new char[1000];
    //construct
    reloc_ptr<A> clsA(base,4, "HI"); //I construct the A with the param "HI"
    //test
    clsA->foo();
    //cleanup
    clsA.destroy();
    delete[] base;
}

reloc_ptr はchar* base、それが構築された元の に対して相対的であることに注意してください。そのため、非常に注意してください。char* base変数が関数内にあり、関数が終了すると、その変数で構築されたすべてのポインターがchar* base無効になり、それらを使用するとプログラムが奇妙なことをします。

http://ideone.com/4DNUGQ

于 2013-06-10T23:56:27.667 に答える
1

あなたが求めているものに非常に似ているのは、C++ の新しい構文の配置です。

配置 new は、演算子 new にメモリを割り当てさせたくない (事前に割り当ててあり、オブジェクトをそこに配置したい) が、オブジェクトを構築したい場合に使用されます。

あなたの例では、メソッド foo() をそれに適用するために、メモリ内の特定の場所にクラス A を割り当てることができます。

void* memoryBuffer;
...
unsigned int i = 0;
for (uint i= 0; i < N; i += offsetSize){
   //initialize a given a specific location in memoryBuffer
   A* a = new(memoryBuffer + i)A(...); 

   //apply foo on that specific memory  location
   a->foo();
}

これは、Eigen を使用して行列オブジェクトを事前に割り当てられた数値バッファーにラップする場合などに追加されるものです。

于 2013-06-10T14:43:26.427 に答える
0

オフセット位置にある type のオブジェクトのアドレス指定について話している場合、A *他の誰かが何らかの方法で移動したオブジェクトは、 のようなものを使用し(clsA+offset)->foo( ... )ます。おそらくメモリ内の「次の」隣接オブジェクトに移動することを意味するため、以前は実際には a になります。offsetsizeof A41

オブジェクトを実際に移動することについて話している場合はnew、メモリ内の新しいアドレスに配置してから、コピー コンストラクター (またはmemcpyPOD の場合) を呼び出すことができますが、これは、オブジェクトが保持するものによってはかなり不安定です。ポインターの所有権と配置を呼び出すと、deleteそのメモリが解放され、かなりSOLになります。

私はこれを十分に強調することはできません.より良い方法があるかもしれないので、あなたが達成しようとしていることを教えてください.

于 2013-06-10T14:51:32.340 に答える