我想这听起来很奇怪,但我正在为硬件设备创建一些低级代码。依赖于特定条件,我需要分配比实际结构需要更多的空间,在那里存储信息并将对象本身的地址传递给调用者。
当用户解除分配这样的对象时,我需要在实际释放对象之前读取这些信息。
目前,我正在使用简单的指针操作来获取地址(类或额外空间)。但是,如果我在内部(!)类型的成员函数中执行指针算术,我认为这将更容易理解。处理地址的分配器是唯一知道这种内部类型的人。换句话说,返回给用户的类型是不同的类型。
以下示例显示了我的意思:
struct foo
{
int& get_x() { return reinterpret_cast<int*>(this)[-2]; }
int& get_y() { return reinterpret_cast<int*>(this)[-1]; }
// actual members of foo
enum { size = sizeof(int) * 2 };
};
int main()
{
char* p = new char[sizeof(foo) + foo::size];
foo* bar = reinterpret_cast<foo*>(p + foo::size);
bar->get_x() = 1;
bar->get_y() = 2;
std::cout << bar->get_x() << ", " << bar->get_y() << std::endl;
delete p;
return 0;
}
这样做是否有争议?
答案 0 :(得分:2)
以这种方式做这似乎是不必要的复杂。如果我要实现这样的东西,我会采取更简单的方法:
#pragma pack(push, 1)
struct A
{
int x, y;
};
struct B
{
int z;
};
#pragma pack(pop)
// allocate space for A and B:
unsigned char* data = new char[sizeof(A) + sizeof(B)];
A* a = reinterpret_cast<A*>(data);
B* b = reinterpret_cast<B*>(a + 1);
a->x = 0;
a->y = 1;
b->z = 2;
// When deallocating:
unsigned char* address = reinterpret_cast<unsigned char*>(a);
delete [] address;
这种实现略有不同,但更容易(在我看来)理解,并且不依赖于对存在或不存在的内容的深入了解。如果指针的所有实例都被分配为unsigned char并被删除,那么除了块中的第一个地址外,用户不需要跟踪特定的内存地址。
答案 1 :(得分:0)
非常简单的想法:将您的额外逻辑包装在一个工厂中,该工厂将为您创建对象并以智能方式删除它们。
答案 2 :(得分:0)
您还可以将结构创建为更大的对象,并使用工厂函数返回结构的实例,但是转换为更小的对象,该对象基本上充当对象的句柄。例如:
struct foo_handle {};
struct foo
{
int a;
int b;
int c;
int d;
int& get_a() { return a; }
int& get_b() { return b; }
//...more member methods
//static factory functions to create and delete objects
static foo_handle* create_obj() { return new foo(); }
static void delete_obj(foo_handle* obj) { delete reinterpret_cast<foo*>(obj); }
};
void another_function(foo_handle* masked_obj)
{
foo* ptr = reinterpret_cast<foo*>(masked_obj);
//... do something with ptr
}
int main()
{
foo_handle* handle = foo::create_obj();
another_function(handle);
foo::delete_obj(handle);
return 0;
}
现在,您可以隐藏foo
结构中可能需要的任何额外空间,并且对于工厂函数的用户,指针的实际值无关紧要,因为它们主要使用不透明的句柄对象。
答案 3 :(得分:0)
您的问题似乎是受欢迎的 struct hack 的候选人。