在什么情况下可以使用指针调配?
In which context can pointer swizzling be used?
我刚刚了解了指针调配,但我不太确定它的实际用途。
例如,假设我有一个 Windows 服务使用某种指针调配序列化包含指针的对象,然后在不同的进程中反序列化它。
它起作用的先决条件是什么?
在我看来它会失败,因为指针试图访问的地址在另一个进程内存中 space 而 OS 将不允许新进程访问它们。指针混合使指针在上下文的变化中幸存下来,但这还不够,不是吗?它还需要首先将数据放在一种共享内存段上,我错了吗?
此外,如果您碰巧知道 C++ 中的任何库以及任何库(如 boost 或其他类似库),我也很想看看实际示例。
当你有 swizzled 指针时,你不能(有效地)跟随它们,直到它们被 unswizzled。
想象一下,如果您有一堆记录,每个记录都有指向其他记录的链接(指针),在某个任意图形中。
混合这些的一种天真的方法是将指针的二进制值作为 UID,并将其序列化。当我们这样做时,我们 也 维护一个 table 的记录地址以在序列化中排序,我们最后序列化它。称其为 swizzle table.
当我们反序列化时,我们加载数据结构,并构建一个 table of (order in serialization) to (new record address in memory)。然后我们加载 swizzle table,它是从(旧地址)到(序列化顺序)的映射。
我们合并这两个 table,我们得到一个(旧地址)到(内存中的新记录地址)table -- unswizzle table.
接下来,我们检查反序列化的记录,并为每个指针应用此映射。每个地址的旧二进制值存储在某个指针中;我们在 unswizzle table 中查看它并替换它。现在每个指针都指向新地址space.
中记录的地址
struct node {
std::vector<node*> links;
void write( OutArch& out ) const& {
out.register_swizzle(this);
out << links.size();
for (node* n:links) {
out << out.swizzle(n);
}
}
static node* read( InArch& in ) {
auto* r = new node;
in.register_unswizzle( r );
std::size_t n;
in >> n;
r->reserve(n);
for (std::size_t i = 0; i<n; ++i) {
std::intptr_t ptr;
in >> ptr;
r->links.push_back( reinterpret_cast<node*>(ptr) ); // danger
}
return r;
}
friend void do_unswizzle( InArch& in, node* n ) {
for (node*& link : n->links ) {
link = in.unswizzle(link);
}
}
};
struct OutArch {
friend void operator<<( OutArch& arch, std::size_t count ); //TODO
friend void operator<<( OutArch& arch, std::intptr_t ptr ); //TODO
std::intptr_t swizzle( void* ptr ) {
return reinterpret_cast<std::intptr_t>(ptr);
}
void register_swizzle( void* ptr ) {
swizzle_table.insert( {(reinterpret_cast<std::intptr_t>(p), record_number} );
++record_number;
}
private:
// increased
std::size_t record_number = 0;
std::map< std::intptr_t, std::size_t > swizzle_table;
};
struct InArch {
friend void operator>>( InArch& arch, std::size_t& count ); //TODO
friend void operator>>( InArch& arch, std::intptr_t& count ); //TODO
template<class T>
void register_unswizzle( T* t ) {
unswizzle_table.insert( {record_number, t} );
++record_number;
unswizzle_tasks.push_back([t](InArch* self){
do_unswizzle( *self, t );
});
}
struct unswizzler_t {
void* ptr;
template<class T>
operator T*()&&{return static_cast<T*>(ptr);}
};
unswizzler_t unswizzle( void* ptr ) {
auto p = reinterpret_cast<std::intptr_t>(ptr);
auto it1 = swizzle_table.find(p);
if (it1 == swizzle_table.end()) return {nullptr};
auto it2 = unswizzle_table.find(it1->second);
if (it2 == unswizzle_table.end()) return {nullptr};
return { it2->second };
}
void load_swizzle_table(); //TODO
void execute_unswizzle() {
for (auto&& task: unswizzle_tasks) {
task(this);
}
}
private:
// increased
std::size_t record_number = 0;
std::map< std::size_t, void* > unswizzle_table;
std::map< std::intptr_t, std::size_t > swizzle_table;
std::vector< std::function< void(InArch*) > > unswizzle_tasks;
};
调配的方法有很多种。您可以保存序列化它的顺序(例如),而不是保存指针的二进制值;但这需要一些仔细的预处理或时间旅行,因为您将引用尚未序列化的结构。
或者您可以生成一个 guid,将 guid 与每条记录一起写出,并在旧过程中将 {record address} 的 swizzle table 保留到 {guid}。当您保存记录时,您会看到指针是否在您的 swizzle 中 table;如果没有,请添加它们。然后写guid而不是指针。在这种情况下不要写 swizzle table; {guid} 到 {record address} 的 unswizzle table 可以从每条记录上的 guid header 构建。然后使用 unswizzle table,重建目标端的记录。
我刚刚了解了指针调配,但我不太确定它的实际用途。
例如,假设我有一个 Windows 服务使用某种指针调配序列化包含指针的对象,然后在不同的进程中反序列化它。
它起作用的先决条件是什么?
在我看来它会失败,因为指针试图访问的地址在另一个进程内存中 space 而 OS 将不允许新进程访问它们。指针混合使指针在上下文的变化中幸存下来,但这还不够,不是吗?它还需要首先将数据放在一种共享内存段上,我错了吗?
此外,如果您碰巧知道 C++ 中的任何库以及任何库(如 boost 或其他类似库),我也很想看看实际示例。
当你有 swizzled 指针时,你不能(有效地)跟随它们,直到它们被 unswizzled。
想象一下,如果您有一堆记录,每个记录都有指向其他记录的链接(指针),在某个任意图形中。
混合这些的一种天真的方法是将指针的二进制值作为 UID,并将其序列化。当我们这样做时,我们 也 维护一个 table 的记录地址以在序列化中排序,我们最后序列化它。称其为 swizzle table.
当我们反序列化时,我们加载数据结构,并构建一个 table of (order in serialization) to (new record address in memory)。然后我们加载 swizzle table,它是从(旧地址)到(序列化顺序)的映射。
我们合并这两个 table,我们得到一个(旧地址)到(内存中的新记录地址)table -- unswizzle table.
接下来,我们检查反序列化的记录,并为每个指针应用此映射。每个地址的旧二进制值存储在某个指针中;我们在 unswizzle table 中查看它并替换它。现在每个指针都指向新地址space.
中记录的地址struct node {
std::vector<node*> links;
void write( OutArch& out ) const& {
out.register_swizzle(this);
out << links.size();
for (node* n:links) {
out << out.swizzle(n);
}
}
static node* read( InArch& in ) {
auto* r = new node;
in.register_unswizzle( r );
std::size_t n;
in >> n;
r->reserve(n);
for (std::size_t i = 0; i<n; ++i) {
std::intptr_t ptr;
in >> ptr;
r->links.push_back( reinterpret_cast<node*>(ptr) ); // danger
}
return r;
}
friend void do_unswizzle( InArch& in, node* n ) {
for (node*& link : n->links ) {
link = in.unswizzle(link);
}
}
};
struct OutArch {
friend void operator<<( OutArch& arch, std::size_t count ); //TODO
friend void operator<<( OutArch& arch, std::intptr_t ptr ); //TODO
std::intptr_t swizzle( void* ptr ) {
return reinterpret_cast<std::intptr_t>(ptr);
}
void register_swizzle( void* ptr ) {
swizzle_table.insert( {(reinterpret_cast<std::intptr_t>(p), record_number} );
++record_number;
}
private:
// increased
std::size_t record_number = 0;
std::map< std::intptr_t, std::size_t > swizzle_table;
};
struct InArch {
friend void operator>>( InArch& arch, std::size_t& count ); //TODO
friend void operator>>( InArch& arch, std::intptr_t& count ); //TODO
template<class T>
void register_unswizzle( T* t ) {
unswizzle_table.insert( {record_number, t} );
++record_number;
unswizzle_tasks.push_back([t](InArch* self){
do_unswizzle( *self, t );
});
}
struct unswizzler_t {
void* ptr;
template<class T>
operator T*()&&{return static_cast<T*>(ptr);}
};
unswizzler_t unswizzle( void* ptr ) {
auto p = reinterpret_cast<std::intptr_t>(ptr);
auto it1 = swizzle_table.find(p);
if (it1 == swizzle_table.end()) return {nullptr};
auto it2 = unswizzle_table.find(it1->second);
if (it2 == unswizzle_table.end()) return {nullptr};
return { it2->second };
}
void load_swizzle_table(); //TODO
void execute_unswizzle() {
for (auto&& task: unswizzle_tasks) {
task(this);
}
}
private:
// increased
std::size_t record_number = 0;
std::map< std::size_t, void* > unswizzle_table;
std::map< std::intptr_t, std::size_t > swizzle_table;
std::vector< std::function< void(InArch*) > > unswizzle_tasks;
};
调配的方法有很多种。您可以保存序列化它的顺序(例如),而不是保存指针的二进制值;但这需要一些仔细的预处理或时间旅行,因为您将引用尚未序列化的结构。
或者您可以生成一个 guid,将 guid 与每条记录一起写出,并在旧过程中将 {record address} 的 swizzle table 保留到 {guid}。当您保存记录时,您会看到指针是否在您的 swizzle 中 table;如果没有,请添加它们。然后写guid而不是指针。在这种情况下不要写 swizzle table; {guid} 到 {record address} 的 unswizzle table 可以从每条记录上的 guid header 构建。然后使用 unswizzle table,重建目标端的记录。