a22_memman03
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
* メモリ管理#3
-(by [[K]], 2022.02.24)
** (1)
-私は C++ が結構好きです。・・・一方で、私は小さなプログ...
-とはいえ、ここからは C++ の話です。
-あるとき、以下のような簡単なクラスを作りたくなりました。
class Test {
public:
const char *nam;
Test(const char *nam_) : nam(nam_) { }
~Test() { printf("%s.deinit\n", nam); }
void print(const char *s) { printf("%s.print: %s\n",...
};
-本当に簡単ですね。コンストラクタは引数を一つ取って、それ...
-(もともとは、このクラスはデストラクタが呼び出されるタイ...
-このTestクラスを使って、以下のようなTest2クラスを作りま...
class Test2 {
public:
Test a, b, c;
Test2(const char *nam) {
int l = strlen(nam);
char *aNam = new char[l + 3];
char *bNam = new char[l + 3];
char *cNam = new char[l + 3];
sprintf(aNam, "%s.a", nam);
sprintf(bNam, "%s.b", nam);
sprintf(cNam, "%s.c", nam);
a(aNam); // ←こんなことはできない.
b(bNam);
c(cNam);
};
(書き途中)
};
-ここまで書いて私は困りました。Test2のコンストラクタ内で...
-しょうがないので、Testクラスから書き換えて以下のようにし...
class Test {
public:
const char *nam;
void init(const char *nam_) { nam = nam_; }
Test() { }
Test(const char *nam_) { init(nam_); }
~Test() { printf("%s.deinit\n", nam); }
void print(const char *s) { printf("%s.print: %s\n",...
};
class Test2 {
public:
Test a, b, c;
Test2(const char *nam) {
int l = strlen(nam);
char *aNam = new char[l + 3];
char *bNam = new char[l + 3];
char *cNam = new char[l + 3];
sprintf(aNam, "%s.a", nam);
sprintf(bNam, "%s.b", nam);
sprintf(cNam, "%s.c", nam);
a.init(aNam);
b.init(bNam);
c.init(cNam);
};
void print(const char *s) {
a.print(s);
b.print(s);
c.print(s);
}
~Test2() {
delete[] a.nam; // ←実はこの書き方はまずい.
delete[] b.nam;
delete[] c.nam;
};
};
int main() // 簡単なテスト用プログラム.
{
Test2 t2("t2");
t2.print("hello");
return 0;
}
-書き直した部分の要点としては、Testクラスにinit()メソッド...
-しかし実行するとうまくいきません。
t2.a.print: hello
t2.b.print: hello
t2.c.print: hello
t2.c.deinit ←ここまでは期待通り、しかし下の2行はお...
・f.deinit
・f.deinit
-なんでこんなことになるのかというと、Testのデストラクタが...
class Test {
public:
const char *nam;
char f; // deinitが実行されたかどうかのフラグ.
void init(const char *nam_) { nam = nam_; }
Test() : f(0) { }
Test(const char *nam_) { init(nam_); }
void deinit() { printf("%s.deinit\n", nam); f = 1; }
~Test() { if (f == 0) deinit(); }
void print(const char *s) { printf("%s.print: %s\n",...
};
class Test2 {
public:
Test a, b, c;
Test2(const char *nam) {
int l = strlen(nam);
char *aNam = new char[l + 3];
char *bNam = new char[l + 3];
char *cNam = new char[l + 3];
sprintf(aNam, "%s.a", nam);
sprintf(bNam, "%s.b", nam);
sprintf(cNam, "%s.c", nam);
a.init(aNam);
b.init(bNam);
c.init(cNam);
};
void print(const char *s) {
a.print(s);
b.print(s);
c.print(s);
}
~Test2() {
a.deinit();
b.deinit();
c.deinit();
delete[] a.nam;
delete[] b.nam;
delete[] c.nam;
};
};
-つまりコンストラクタの実体をinitに移し替えたのと同じよう...
-これを実行すると、
t2.a.print: hello
t2.b.print: hello
t2.c.print: hello
t2.a.deinit
t2.b.deinit
t2.c.deinit
-となって、やっと期待通りになりました。
-しかしそれにしても、なぜこんな面倒なことになったのでしょ...
** (2)
-似たようなことをC言語でもやってみることにします。
typedef struct Test_ {
const char *nam;
} Test;
void Test_deinit(Test *t) { printf("%s.deinit\n", t->nam...
void Test_init(Test *t, const char *nam, Clean *c) { t->...
void Test_print(Test *t, const char *s) { printf("%s.pri...
typedef struct Test2_ {
Clean cln;
Test a, b, c;
} Test2;
void Test2_deinit(Test2 *t) { Clean_out(&t->cln); }
void Test2_init(Test2 *t, const char *nam, Clean *c) {
Clean_init(&t->cln);
int l = strlen(nam);
char *aNam = Clean_malloc(&t->cln, l + 3);
char *bNam = Clean_malloc(&t->cln, l + 3);
char *cNam = Clean_malloc(&t->cln, l + 3);
sprintf(aNam, "%s.a", nam);
sprintf(bNam, "%s.b", nam);
sprintf(cNam, "%s.c", nam);
Test_init(&t->a, aNam, &t->cln);
Test_init(&t->b, bNam, &t->cln);
Test_init(&t->c, cNam, &t->cln);
Clean_set(c, Test2_deinit, t);
};
void Test2_print(Test2 *t, const char *s) {
Test_print(&t->a, s);
Test_print(&t->b, s);
Test_print(&t->c, s);
}
int main() // 簡単なテスト用プログラム.
{
Test2 t2;
Test2_init(&t2, "t2");
Test2_print(&t2, "hello");
Test2_deinit(&t2);
return 0;
}
-C++版はmain以外で41行もありましたが、C版は31行で済みまし...
typedef struct CleanSub_ {
void *f, *p, *next;
} CleanSub;
typedef struct Clean_ {
CleanSub *sub;
} Clean;
void Clean_init(Clean *c) { c->sub = 0; }
void Clean_out(Clean *c) {
CleanSub *s, *s0;
for (s = c->sub; s != 0; ) {
void (*fnc)(void *);
fnc = s->f;
fnc(s->p);
s0 = s;
s = s->next;
free(s0);
}
c->sub = 0;
}
void Clean_set(Clean *c, void *f, void *p) {
if (c != 0) {
CleanSub *s = malloc(sizeof (CleanSub));
s->next = c->sub;
c->sub = s;
s->f = f;
s->p = p;
}
}
void *Clean_malloc(Clean *c, int sz) {
void *p = malloc(sz);
Clean_set(c, free, p);
return p;
}
-もしCleanを全く使わない実装にすると、Test2_deinitはこう...
void Test2_deinit(Test2 *t) {
Test_deinit(&t->a);
Test_deinit(&t->b);
Test_deinit(&t->c);
free(&t->a);
free(&t->b);
free(&t->c);
}
-そして、C++版とC言語版で実行ファイルサイズを比較するとこ...
|C++版|RIGHT:21,504|
|C言語版(Clean使用)|RIGHT:6,144|
|C言語版(Cleanなし)|RIGHT:6,144|
-ただしC言語版(Clean使用)が無条件に優秀というわけではない...
* (3)
-[Q] これって、C++版のTestクラスのデストラクタ内で、delet...
-[A] そういう仕様にすることもできますが、それだと、Test t...
-[Q] じゃあさあ、Testのコンストラクタは常に渡された名前の...
-[A] それで動作は問題なくなりますが、「不要な時でもコピー...
終了行:
* メモリ管理#3
-(by [[K]], 2022.02.24)
** (1)
-私は C++ が結構好きです。・・・一方で、私は小さなプログ...
-とはいえ、ここからは C++ の話です。
-あるとき、以下のような簡単なクラスを作りたくなりました。
class Test {
public:
const char *nam;
Test(const char *nam_) : nam(nam_) { }
~Test() { printf("%s.deinit\n", nam); }
void print(const char *s) { printf("%s.print: %s\n",...
};
-本当に簡単ですね。コンストラクタは引数を一つ取って、それ...
-(もともとは、このクラスはデストラクタが呼び出されるタイ...
-このTestクラスを使って、以下のようなTest2クラスを作りま...
class Test2 {
public:
Test a, b, c;
Test2(const char *nam) {
int l = strlen(nam);
char *aNam = new char[l + 3];
char *bNam = new char[l + 3];
char *cNam = new char[l + 3];
sprintf(aNam, "%s.a", nam);
sprintf(bNam, "%s.b", nam);
sprintf(cNam, "%s.c", nam);
a(aNam); // ←こんなことはできない.
b(bNam);
c(cNam);
};
(書き途中)
};
-ここまで書いて私は困りました。Test2のコンストラクタ内で...
-しょうがないので、Testクラスから書き換えて以下のようにし...
class Test {
public:
const char *nam;
void init(const char *nam_) { nam = nam_; }
Test() { }
Test(const char *nam_) { init(nam_); }
~Test() { printf("%s.deinit\n", nam); }
void print(const char *s) { printf("%s.print: %s\n",...
};
class Test2 {
public:
Test a, b, c;
Test2(const char *nam) {
int l = strlen(nam);
char *aNam = new char[l + 3];
char *bNam = new char[l + 3];
char *cNam = new char[l + 3];
sprintf(aNam, "%s.a", nam);
sprintf(bNam, "%s.b", nam);
sprintf(cNam, "%s.c", nam);
a.init(aNam);
b.init(bNam);
c.init(cNam);
};
void print(const char *s) {
a.print(s);
b.print(s);
c.print(s);
}
~Test2() {
delete[] a.nam; // ←実はこの書き方はまずい.
delete[] b.nam;
delete[] c.nam;
};
};
int main() // 簡単なテスト用プログラム.
{
Test2 t2("t2");
t2.print("hello");
return 0;
}
-書き直した部分の要点としては、Testクラスにinit()メソッド...
-しかし実行するとうまくいきません。
t2.a.print: hello
t2.b.print: hello
t2.c.print: hello
t2.c.deinit ←ここまでは期待通り、しかし下の2行はお...
・f.deinit
・f.deinit
-なんでこんなことになるのかというと、Testのデストラクタが...
class Test {
public:
const char *nam;
char f; // deinitが実行されたかどうかのフラグ.
void init(const char *nam_) { nam = nam_; }
Test() : f(0) { }
Test(const char *nam_) { init(nam_); }
void deinit() { printf("%s.deinit\n", nam); f = 1; }
~Test() { if (f == 0) deinit(); }
void print(const char *s) { printf("%s.print: %s\n",...
};
class Test2 {
public:
Test a, b, c;
Test2(const char *nam) {
int l = strlen(nam);
char *aNam = new char[l + 3];
char *bNam = new char[l + 3];
char *cNam = new char[l + 3];
sprintf(aNam, "%s.a", nam);
sprintf(bNam, "%s.b", nam);
sprintf(cNam, "%s.c", nam);
a.init(aNam);
b.init(bNam);
c.init(cNam);
};
void print(const char *s) {
a.print(s);
b.print(s);
c.print(s);
}
~Test2() {
a.deinit();
b.deinit();
c.deinit();
delete[] a.nam;
delete[] b.nam;
delete[] c.nam;
};
};
-つまりコンストラクタの実体をinitに移し替えたのと同じよう...
-これを実行すると、
t2.a.print: hello
t2.b.print: hello
t2.c.print: hello
t2.a.deinit
t2.b.deinit
t2.c.deinit
-となって、やっと期待通りになりました。
-しかしそれにしても、なぜこんな面倒なことになったのでしょ...
** (2)
-似たようなことをC言語でもやってみることにします。
typedef struct Test_ {
const char *nam;
} Test;
void Test_deinit(Test *t) { printf("%s.deinit\n", t->nam...
void Test_init(Test *t, const char *nam, Clean *c) { t->...
void Test_print(Test *t, const char *s) { printf("%s.pri...
typedef struct Test2_ {
Clean cln;
Test a, b, c;
} Test2;
void Test2_deinit(Test2 *t) { Clean_out(&t->cln); }
void Test2_init(Test2 *t, const char *nam, Clean *c) {
Clean_init(&t->cln);
int l = strlen(nam);
char *aNam = Clean_malloc(&t->cln, l + 3);
char *bNam = Clean_malloc(&t->cln, l + 3);
char *cNam = Clean_malloc(&t->cln, l + 3);
sprintf(aNam, "%s.a", nam);
sprintf(bNam, "%s.b", nam);
sprintf(cNam, "%s.c", nam);
Test_init(&t->a, aNam, &t->cln);
Test_init(&t->b, bNam, &t->cln);
Test_init(&t->c, cNam, &t->cln);
Clean_set(c, Test2_deinit, t);
};
void Test2_print(Test2 *t, const char *s) {
Test_print(&t->a, s);
Test_print(&t->b, s);
Test_print(&t->c, s);
}
int main() // 簡単なテスト用プログラム.
{
Test2 t2;
Test2_init(&t2, "t2");
Test2_print(&t2, "hello");
Test2_deinit(&t2);
return 0;
}
-C++版はmain以外で41行もありましたが、C版は31行で済みまし...
typedef struct CleanSub_ {
void *f, *p, *next;
} CleanSub;
typedef struct Clean_ {
CleanSub *sub;
} Clean;
void Clean_init(Clean *c) { c->sub = 0; }
void Clean_out(Clean *c) {
CleanSub *s, *s0;
for (s = c->sub; s != 0; ) {
void (*fnc)(void *);
fnc = s->f;
fnc(s->p);
s0 = s;
s = s->next;
free(s0);
}
c->sub = 0;
}
void Clean_set(Clean *c, void *f, void *p) {
if (c != 0) {
CleanSub *s = malloc(sizeof (CleanSub));
s->next = c->sub;
c->sub = s;
s->f = f;
s->p = p;
}
}
void *Clean_malloc(Clean *c, int sz) {
void *p = malloc(sz);
Clean_set(c, free, p);
return p;
}
-もしCleanを全く使わない実装にすると、Test2_deinitはこう...
void Test2_deinit(Test2 *t) {
Test_deinit(&t->a);
Test_deinit(&t->b);
Test_deinit(&t->c);
free(&t->a);
free(&t->b);
free(&t->c);
}
-そして、C++版とC言語版で実行ファイルサイズを比較するとこ...
|C++版|RIGHT:21,504|
|C言語版(Clean使用)|RIGHT:6,144|
|C言語版(Cleanなし)|RIGHT:6,144|
-ただしC言語版(Clean使用)が無条件に優秀というわけではない...
* (3)
-[Q] これって、C++版のTestクラスのデストラクタ内で、delet...
-[A] そういう仕様にすることもできますが、それだと、Test t...
-[Q] じゃあさあ、Testのコンストラクタは常に渡された名前の...
-[A] それで動作は問題なくなりますが、「不要な時でもコピー...
ページ名: