char型をnewしたあと初期化するには?

解決


かつや  2008-04-21 08:57:50  No: 68091

C++なのですが、char型の200個文の配列をnewしたあと、
その領域を0初期化したいのですが、
どうすればよいでしょうか?
以下のようにmemsetで0初期化してしまって問題ないでしょうか?

char* c = new char[200];
memset(c, 0, 200);

また、デフォルトコンストラクタで適切にメンバ変数を
初期化していないクラスがあったとして、
そのクラスを強制的に初期化する際にもmemsetを使ってよいものでしょうか?

class A{
 int i;
};

A* a = new A();
memset(a, 0, sizeof(A));

それとも他のやり方があるのでしょうか?
よろしくお願いします。


そだ  2008-04-21 10:23:53  No: 68092

>以下のようにmemsetで0初期化してしまって問題ないでしょうか?
mallocの親戚にcallocという関数があるけど
newで作ってmemsetで初期化してでいいんじゃないでしょうか。
小心者な私は memset(c, 0, 200*sizeof(char))と書いてしまいますが
それはさておき

>class A{
> int i;
>};
>A* a = new A();
>memset(a, 0, sizeof(A));

構造体ならともかくクラスでこれはないかと・・・
と言いつつ自信がないので裏付けを。
http://oshiete1.goo.ne.jp/qa2007539.html

ところでsizeof(class name)ってどうなるんだろうなぁと思ったら
検証している人いるんですねぇ
http://www.s34.co.jp/cpptechdoc/article/sizeof/index.html
使いどころがやっぱりわかりませんが。


YuO  2008-04-21 11:29:04  No: 68093

> C++なのですが、char型の200個文の配列をnewしたあと、
> その領域を0初期化したいのですが、
> どうすればよいでしょうか?

0に設定したいなら,std::fill_nあたりが普通かと。
まぁ,charならmemsetでもよいですが……。
# 0初期化→確保したオブジェクト全てに0を設定したいと読み替えました。

基本的に,配列へ値を設定するにはmemsetではなくstd::fillやstd::fill_nといったものを使うようにするのがよいです。

> また、デフォルトコンストラクタで適切にメンバ変数を
> 初期化していないクラスがあったとして、
> そのクラスを強制的に初期化する際にもmemsetを使ってよいものでしょうか?

それは「初期化」とは呼びません。
それはともかく,PODならmemset使ってもよいですが,そうでないならmemsetはまずいです。

コンストラクタで正しく初期化する事をお勧めします。

> class A{
>  int i;
> };

class A {
  int i;
public:
  A(int iVal = 0) : i(iVal) {}
};


επιστημη  2008-04-21 15:24:11  No: 68094

> A* a = new A();
> memset(a, 0, sizeof(A));

Aが仮想関数を持ってたらアウトでしょうね。


かつや  2008-04-21 16:28:45  No: 68095

そださん、参考リンクありがとうございます。
勉強になりました。

YuOさん、std::fillの利用を検討してみます。
ありがとうございます。

επιστημηさんありがとうございます。
vptrの分の4バイトをずらしてやればよいのでしょうか?
class A
{
virtual Func();
int i;
};

A* a = new A();
char* a_ptr = (char*)a;
memset(a[4], 0, sizeof(A) - 4);


かつや  2008-04-21 16:30:20  No: 68096

すみません。寝ぼけていました。
上のコードを以下に訂正させてください。

class A
{
virtual void Func();
int i;
};

A* a = new A();
char* a_ptr = (char*)a;
memset(a_ptr[4], 0, sizeof(A) - 4);


wclrp ( 'o')  2008-04-21 17:11:38  No: 68097

4バイトずらすとかは駄目。
移植性とか一切考慮しないで動けばいいっていう方法だな。

4バイトって決まりないし。
先頭に1つだけという決まりじゃないし。


επιστημη  URL  2008-04-21 18:12:13  No: 68098

> 4バイトって決まりないし。
> 先頭に1つだけという決まりじゃないし。

御意。

A* a_ptr = new A[10];
だったらどっちみちアウトだし。


あー  2008-04-22 06:22:38  No: 68099

http://d.hatena.ne.jp/uskz/20080421/p1
一応


YuO  2008-04-22 08:06:35  No: 68100

慌てて規格書読み返しましたが,確かに配列の時に()を付けてはいけないという制約はないですね。
書かれている通り,value-initializedは可能なようです。

でも,確かに盲点……。
char * c = char[200]();
ってのは,なかなか思いつかない……。


かつや  2008-04-22 09:30:23  No: 68101

wclrp ( 'o')さんありがとうございます。
おっしゃる通り強引で移植性のないやり方でした。

επιστημηさんありがとうございます。
すみません。
以下なのですが、どうしてそれだとアウトなのか
理解できなかったです。

>A* a_ptr = new A[10];
>だったらどっちみちアウトだし。

あー さんありがとうございます。
char* c = new char[200]();
と()をつけると確かにVC2008だと初期化されていました。
()をつけないと未初期化状態でした。
C++でnewを利用するとき、new CLASSとしてもnew CLASS()としても、
スタイルの問題で動作には違いがないとばかり思っていました。
驚きです。組み込み型であれば、newするときに()をつけるかつけないかで
初期化されるかされないかという違いがあるのですね。

YuOさんありがとうございます。
組み込み型をnewする際に()をつけると0初期化してくれる動作のことを
value-initializedと呼ぶのですね。


επιστημη  2008-04-22 10:09:49  No: 68102

> 以下なのですが、どうしてそれだとアウトなのか
> 理解できなかったです。
>
>> A* a_ptr = new A[10];
>> だったらどっちみちアウトだし。

その後 10個分をmemsetで0クリアすると
どうやっても仮想関数ポインタを破壊するっしょ?

繰り返しになりますが、0で埋めることが初期化じゃありません。


シャノン  2008-04-22 20:06:29  No: 68103

char配列を文字列として使うなら、c[0] = '\0'; で十分だというのは言っちゃダメ?
# 生理的にゼロクリアしたい気持ちはわかりますが、最近はやらない派になりました。


かつや  2008-04-23 09:48:01  No: 68104

επιστημηさんありがとうございます。
ようやく理解できました。

シャノンさんありがとうございます。
ゼロクリアをやらない派になった理由をよろしければ
お聞かせ願えないでしょうか?
興味があります。


επιστημη  URL  2008-04-23 15:01:46  No: 68105

文字列であるなら、'\0'以降は無意味だから。


シャノン  2008-04-24 00:45:21  No: 68106

加えて、Windows API なんかを使っていると、構造体に「どのメンバを使うかフラグ」を持っている場合があり、そのフラグに含めていないメンバは未初期化でも問題ないから。
# 今回の本題じゃないけどね。


かつや  2008-04-25 09:49:28  No: 68107

επιστημηさん、シャノンさん
ありがとうございました。

解決といたします。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加