C ++访问内存,它不是对象本身的一部分

时间:2011-07-05 12:50:37

标签: c++ pointers low-level

我想这听起来很奇怪,但我正在为硬件设备创建一些低级代码。依赖于特定条件,我需要分配比实际结构需要更多的空间,在那里存储信息并将对象本身的地址传递给调用者。

当用户解除分配这样的对象时,我需要在实际释放对象之前读取这些信息。

目前,我正在使用简单的指针操作来获取地址(类或额外空间)。但是,如果我在内部(!)类型的成员函数中执行指针算术,我认为这将更容易理解。处理地址的分配器是唯一知道这种内部类型的人。换句话说,返回给用户的类型是不同的类型。

以下示例显示了我的意思:

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;
}

这样做是否有争议?

4 个答案:

答案 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 的候选人。

Is the "struct hack" technically undefined behavior?