-1

我想知道是否可以使用动态基地址而不是静态基地址来寻址一个类。基本思路如下:

有一个对象 A 定义如下:

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

此类不能实例化为堆栈对象,并且没有标准的 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) 中完成,但我想要一个具有尽可能多的可移植性的解决方案(我承认它仍然几乎没有,但总比没有好)。有什么建议么?

编辑:所以我想我不太清楚我遇到的问题。这个想法是允许动态对象(在堆上分配的对象)在内存中移动。通常这不会有问题,但是由于无法通过堆栈内存实例化对象,因此访问对象的唯一方法是通过指向对象底层内存的指针。当数组移动时(在示例中,移动了四个字节),从数组借出的指针不再有效,需要更新。由于这个过程不仅会很长,而且会消耗比我希望的更多的内存,所以我希望能够让类在访问时重新计算它们的内存地址,而不是为每个借出的指针存储一个带有条目的重定位表。

一些可能代表这个概念的程序集是

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

编辑 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++ 的放置新语法

当您不希望 operator new 分配内存(您已经预先分配它并且您希望将对象放置在那里)但您确实希望构造对象时,使用 Placement new。

在您的示例中,您可能会在内存中的特定位置分配一个类 A,以便随后将方法 foo() 应用于它。

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

If you're talking about addressing the object of type A * at an offset position, an object someone else moved somehow, you'd use something like (clsA+offset)->foo( ... ), where offset is in sizeof A units, ie. your earlier 4 would actually be a 1 because you probably mean to move to the "next" adjacent object in memory.

If you're talking about actually moving the object, you can placement-new at the new address in memory, then call the copy constructor (or memcpy for a POD), but this is pretty iffy depending on what your object holds, if it insists on ownership of pointers and when you call placement-delete that memory gets freed you're pretty SOL.

I can't emphasize this enough, tell us what you're trying to accomplish because there might be a better way, this is pretty against the proverbial grain right here.

于 2013-06-10T14:51:32.340 回答