はじめまして
環境
MS Visual studio 2012 でVC++
シリアライズという言葉を良く耳にしますが、
概念的に理解できないところがあります。
例えば、構造体の中に関数ポインタがあるとします。
仮令同じ関数を指していても、
関数ポインタの設定内容はそのメモリ環境においてのみ有効であって、場によって異なってくると思います。
なので、デシリアライズで復元された関数ポインタで関数を有効にコールする事はできるのでしょうか。
もしできるなら、どうしてできるのでしょうか。
ご存知の方ご教授いただければ幸いです。
構造体の直列化(Persistency)
Re: 構造体の直列化(Persistency)
関数ポインタにかぎらず、ポインタは基本的にシリアライズ出来ません。
仰るとおり、そのメモリ環境においてのみ有効だからです。
無理やりポインタをアドレスを表す整数値としてシリアライズし、それをデシリアライズしてもでたらめなメモリ位置を指し示すだけで、使い物になりません。
仰るとおり、そのメモリ環境においてのみ有効だからです。
無理やりポインタをアドレスを表す整数値としてシリアライズし、それをデシリアライズしてもでたらめなメモリ位置を指し示すだけで、使い物になりません。
Re: 構造体の直列化(Persistency)
関数ポインタと文字列を相互変換できるようにしてシリアライズする、という方法もあります。
簡易的ですがこんな感じです。
簡易的ですがこんな感じです。
#include <stdio.h>
typedef void (*FuncPtr)();
#define TABLE_SIZE 2
void funcA() {
puts("funcA called");
}
void funcB() {
puts("funcB called");
}
typedef struct {
char* name;
FuncPtr func;
} FuncTableItem;
// 文字列と関数ポインタの対応テーブル
FuncTableItem table[TABLE_SIZE] = {
{"funcA", funcA},
{"funcB", funcB}
};
// 文字列から関数ポインタへ変換
FuncPtr name2func(const char *name) {
int i;
for (i = 0; i < TABLE_SIZE; ++i) {
if (strcmp(table[i].name, name) == 0)
return table[i].func;
}
return NULL;
}
// 関数ポインタから文字列へ変換
const char* func2name(FuncPtr func) {
int i;
for (i = 0; i < TABLE_SIZE; ++i) {
if (table[i].func == func)
return table[i].name;
}
return NULL;
}
typedef struct {
FuncPtr func;
} Foo;
void serialize(char *data, const Foo* foo) {
sprintf(data, "%s", func2name(foo->func));
}
void deserialize(Foo* foo, const char *data) {
foo->func = name2func(data);
}
int main(void) {
Foo f, f2;
char data[256] = {0};
// fの内容をシリアライズ
f.func = funcB;
serialize(data, &f);
// f2にデシリアライズ
deserialize(&f2, data);
f2.func();
return 0;
}
Re: 構造体の直列化(Persistency)
シリアライズ時にポインタや関数ポインタ,メンバへのポインタなどを考慮して作れば可能です。
基本的には,オブジェクトや関数,メンバにIDを振っておいて,ポインタの代わりにそのIDを保存します。
非ポインタ,非参照なサブオブジェクトへのポインタも考慮する必要がありますが。
# ポインタ自体がIDといえばIDですが,あくまでシリアライズ時に振り直す必要がある
基本的には,オブジェクトや関数,メンバにIDを振っておいて,ポインタの代わりにそのIDを保存します。
非ポインタ,非参照なサブオブジェクトへのポインタも考慮する必要がありますが。
# ポインタ自体がIDといえばIDですが,あくまでシリアライズ時に振り直す必要がある
Re: 構造体の直列化(Persistency)
皆様丁寧なご指導ありがとうございます。
h2so5様がコードまで組んで下さって分かりやすかったのです。
ただ、ポインタの存在はC言語の付き物で、C#やboostあたりでポインタまで
有効にシリアライズしてくれるツールはないでしょうか。
また宜しくお願い致します。
h2so5様がコードまで組んで下さって分かりやすかったのです。
ただ、ポインタの存在はC言語の付き物で、C#やboostあたりでポインタまで
有効にシリアライズしてくれるツールはないでしょうか。
また宜しくお願い致します。
Re: 構造体の直列化(Persistency)
シリアライズ関連のライブラリとしてはBoost.Serializationなどがあります。
シリアライズ可能な型へのポインタも再帰的にシリアライズできるみたいですね。
シリアライズ可能な型へのポインタも再帰的にシリアライズできるみたいですね。
Re: 構造体の直列化(Persistency)
ポインタに限らず,オブジェクトのシリアライズが最終的には自分で実装になるのがC/C++です。雅子鈴木 さんが書きました:ただ、ポインタの存在はC言語の付き物で、C#やboostあたりでポインタまで
有効にシリアライズしてくれるツールはないでしょうか。
boost::serializerも,ポインタが指す実体のトラッキングはしてくれますが,クラスのシリアライズコード自体は自分で書かないといけません。
ref) http://daily.belltail.jp/?p=345
C#というか.NET Frameworkでは,リフレクション機能があることと,任意の位置へのポインタがないために,
.NET Framework 1.0からBinaryFormatterやXmlSerializerといったシリアライザが用意されています。
他にもDataContractSerializer系のWCF由来のシリアライザやSystem.JsonのようなMS製だけどNuget経由で入れる物,JSON.net等のユーザー製作のシリアライザも存在します。
# オブジェクトグラフのノードを複数回辿らないように注意すれば,独自のシリアライザを書くことも可能ではある。
ただし,C++/CLIでunmanaged pointer使ったり,C#でunsafe pointer使った場合に,シリアライザがまともに動作するかはわかりませんが。