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

解決


かつや  2008-04-20 23:57:50  No: 68091  IP: 192.*.*.*

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 01:23:53  No: 68092  IP: 192.*.*.*

>以下のように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 02:29:04  No: 68093  IP: 192.*.*.*

> 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 06:24:11  No: 68094  IP: 192.*.*.*

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

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

編集 削除
かつや  2008-04-21 07:28:45  No: 68095  IP: 192.*.*.*

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

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 07:30:20  No: 68096  IP: 192.*.*.*

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

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 08:11:38  No: 68097  IP: 192.*.*.*

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

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

編集 削除
επιστημη  URL  2008-04-21 09:12:13  No: 68098  IP: 192.*.*.*

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

御意。

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

編集 削除
あー  2008-04-21 21:22:38  No: 68099  IP: 192.*.*.*

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

編集 削除
YuO  2008-04-21 23:06:35  No: 68100  IP: 192.*.*.*

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

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

編集 削除
かつや  2008-04-22 00:30:23  No: 68101  IP: 192.*.*.*

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 01:09:49  No: 68102  IP: 192.*.*.*

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

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

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

編集 削除
シャノン  2008-04-22 11:06:29  No: 68103  IP: 192.*.*.*

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

編集 削除
かつや  2008-04-23 00:48:01  No: 68104  IP: 192.*.*.*

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

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

編集 削除
επιστημη  URL  2008-04-23 06:01:46  No: 68105  IP: 192.*.*.*

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

編集 削除
シャノン  2008-04-23 15:45:21  No: 68106  IP: 192.*.*.*

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

編集 削除
かつや  2008-04-25 00:49:28  No: 68107  IP: 192.*.*.*

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

解決といたします。

編集 削除