在C++中,有没有一种方法可以将我想要的布局“映射”到内存数据上,而不用进行内存复制?
即。 有一个void*buffer
,我知道它的布局:
我知道我可以创建一个struct,并将数据memcpy到struct,然后我可以将值作为struct的字段。
但是,有没有一种不用抄袭就能做到这一点的方法呢? 数据已经在那里,我只需要得到一些字段,我正在寻找一种方式,为一些东西可以帮助与布局。
(我可以有一些static int
用于内存偏移量,但我希望有一些更通用的)。
即:我会有更多的“布局”,并且基于原始数据的类型,我会映射适当的布局并访问其字段,这些字段仍然指向原始数据。
我知道我可以将结构指向数据,这很容易:
struct message {
uint8_t type;
};
struct request:message {
uint8_t rid;
uint8_t other;
};
struct response:message {
uint8_t result;
};
vector<uint8_t> data;
data.push_back(1); //type
data.push_back(10);
data.push_back(11);
data.push_back(12);
data.push_back(13);
struct request* ptrRequest;
ptrRequest = (struct request*)&data[1];
cout << (int)ptrRequest->rid; //10
cout << (int)ptrRequest->other; //11
但我想要实现的是有一个包含布局的地图,即:
map<int, struct message*> messagetypes;
但是我不知道如何才能继续,因为定位需要一个新的对象,而且如果地图只存储基本指针的话,施法也是很有挑战性的。
在C++中,有没有一种方法可以将我想要的布局“映射”到内存数据上,而不用进行内存复制?
不,不是在标准C++中。
如果布局与类1的布局匹配,那么您可能能够做的是首先将内存数据写入类实例,这样之后就不需要进行复制。
如果上述方法不可行,那么您可以将数据复制(是的,这是memcopy,但保持这种想法)到类的一个自动实例上,然后将自动实例的一个副本重新放置到源数组上。 一个好的优化者可以看到这些来回的拷贝不会改变值,并且可以把它们优化掉。 匹配布局在这里也是必要的。 示例:
struct data {
std::uint8_t byte;
std::uint8_t another;
std::uint16_t properly_aligned;
};
void* buffer = get_some_buffer();
if (!std::align(alignof(data), sizeof(data), buffer, space))
throw std::invalid_argument("bad alignment");
data local{};
std::memcpy(&local, buffer, sizeof local);
data* dataptr = new(buffer) data{local};
std::uint16_t value_from_offset = dataptr->properly_aligned;
https://godbolt.org/z/uvrxs2注意,在生成的程序集中没有调用std::memcpy
。
1然而,数据似乎不太可能匹配类的布局,因为第二个元素UINT16_T
没有从布局开始对齐到两个16位边界。
如果您的布局结构是POD,您可以在不初始化的情况下执行placement new-expression,这将作为对象创建标记。 例如:
#include <new> // Placement new.
// ...
uint8_t* data = ...; // Read from disk, network, or elsewhere.
static_assert(std::is_pod<request>::value, "struct request must be POD.");
request* ptrRequest = new (static_cast<void*>(data)) request;
这只适用于豆荚。 这是在P0593R6隐式创建用于低级对象操作的对象中记录的一个长期存在的问题。
如果您的目标体系结构要求数据对齐,请添加data
指针对齐检查。
另一个答案指出,memcpy
可能被编译器删除,请检查程序集输出。