C++访问不属于对象本身的内存

发布于 2024-11-18 16:03:50 字数 842 浏览 6 评论 0原文

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

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

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

下面的例子说明了我的意思:

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

这样做有争议吗?

It sounds weird, I guess, but I'm creating some low-level code for a hardware device. Dependend on specific conditions I need to allocate more space than the actual struct needs, store informations there and pass the address of the object itself to the caller.

When the user is deallocating such an object, I need to read these informations before I actually deallocate the object.

At the moment, I'm using simple pointer operations to get the addresses (either of the class or the extra space). However, I tought it would be more understandable if I do the pointer arithmetics in member functions of an internal (!) type. The allocator, which is dealing with the addresses, is the only one who know's about this internal type. In other words, the type which is returned to the user is a different one.

The following example show's what I mean:

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

Is it arguable to do it in that way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

舟遥客 2024-11-25 16:03:50

这样做似乎不必要地复杂。如果我要实现这样的东西,我会采取一种更简单的方法:

#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 并按此删除,则用户不需要跟踪除块中的第一个地址之外的特定内存地址。

It seems needlessly complex to do it this way. If I were to implement something like this, I would take a simpler approach:

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

This implementation is subtly different, but much easier (in my opinion) to understand, and doesn't rely on intimate knowledge of what is or is not present. If all instances of the pointers are allocated as unsigned char and deleted as such, the user doesn't need to keep track of specific memory addresses aside from the first address in the block.

铜锣湾横着走 2024-11-25 16:03:50

非常简单的想法:将额外的逻辑包装在工厂中,该工厂将为您创建对象并以智能方式删除它们。

The very straightforward idea: wrap your extra logic in a factory which will create objects for you and delete them smart way.

数理化全能战士 2024-11-25 16:03:50

您还可以将结构创建为一个更大的对象,并使用工厂函数返回该结构的实例,但转换为一个更小的对象,该对象基本上充当该对象的句柄。例如:

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 结构中可能需要的任何额外空间,对于工厂函数的用户来说,指针的实际值并不重要,因为它们主要与对象的不透明句柄。

You can also create the struct as a much larger object, and use a factory function to return an instance of the struct, but cast to a much smaller object that would basically act as the object's handle. For instance:

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

Now you can hide any extra space you may need in your foo struct, and to the user of your factory functions, the actual value of the pointer doesn't matter since they are mainly working with an opaque handle to the object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文