我想知道是否可以使用动态基地址而不是静态地址来处理类。基本思路如下:
让对象A定义如下:
class A
{
//member variables
...
//non-virtual member functions
...
//virtual methods
virtual void foo(...);
...
};
此类无法实例化为堆栈对象,并且没有标准的新运算符。
相反,该对象有一个placement 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声明相对于另一个指针的指针,因此可以移动底层内存并且指针保持有效。这篇文章是 here。
答案 0 :(得分:1)
与您提出的问题非常相似的是C ++的placement new syntax。
如果您不希望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附加在预分配的数字缓冲区周围包装矩阵对象的内容。
答案 1 :(得分: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
变量构造的所有指针都将变为无效,并且使用它们将使程序执行奇怪的操作。
答案 2 :(得分:0)
如果您正在谈论在偏移位置处理A *
类型的对象,其他人以某种方式移动的对象,您会使用类似(clsA+offset)->foo( ... )
的内容,其中offset
是以sizeof A
为单位,即。您之前的4
实际上是1
,因为您可能想要移动到内存中的“下一个”相邻对象。
如果您正在谈论实际移动对象,您可以将 - new
放置在内存中的新地址,然后调用复制构造函数(或memcpy
作为POD),但这是非常iffy取决于你的对象持有什么,如果它坚持指针的所有权和你调用放置 - delete
内存得到释放你是非常SOL。
我不能强调这一点,告诉我们你想要完成什么,因为可能有一个更好的方法,这在很好地反对众所周知的谷物。