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));
それとも他のやり方があるのでしょうか?
よろしくお願いします。
>以下のように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
使いどころがやっぱりわかりませんが。
> 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) {}
};
> A* a = new A();
> memset(a, 0, sizeof(A));
Aが仮想関数を持ってたらアウトでしょうね。
そださん、参考リンクありがとうございます。
勉強になりました。
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);
すみません。寝ぼけていました。
上のコードを以下に訂正させてください。
class A
{
virtual void Func();
int i;
};
A* a = new A();
char* a_ptr = (char*)a;
memset(a_ptr[4], 0, sizeof(A) - 4);
4バイトずらすとかは駄目。
移植性とか一切考慮しないで動けばいいっていう方法だな。
4バイトって決まりないし。
先頭に1つだけという決まりじゃないし。
> 4バイトって決まりないし。
> 先頭に1つだけという決まりじゃないし。
御意。
A* a_ptr = new A[10];
だったらどっちみちアウトだし。
http://d.hatena.ne.jp/uskz/20080421/p1
一応
慌てて規格書読み返しましたが,確かに配列の時に()を付けてはいけないという制約はないですね。
書かれている通り,value-initializedは可能なようです。
でも,確かに盲点……。
char * c = char[200]();
ってのは,なかなか思いつかない……。
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と呼ぶのですね。
> 以下なのですが、どうしてそれだとアウトなのか
> 理解できなかったです。
>
>> A* a_ptr = new A[10];
>> だったらどっちみちアウトだし。
その後 10個分をmemsetで0クリアすると
どうやっても仮想関数ポインタを破壊するっしょ?
繰り返しになりますが、0で埋めることが初期化じゃありません。
char配列を文字列として使うなら、c[0] = '\0'; で十分だというのは言っちゃダメ?
# 生理的にゼロクリアしたい気持ちはわかりますが、最近はやらない派になりました。
επιστημηさんありがとうございます。
ようやく理解できました。
シャノンさんありがとうございます。
ゼロクリアをやらない派になった理由をよろしければ
お聞かせ願えないでしょうか?
興味があります。
文字列であるなら、'\0'以降は無意味だから。
加えて、Windows API なんかを使っていると、構造体に「どのメンバを使うかフラグ」を持っている場合があり、そのフラグに含めていないメンバは未初期化でも問題ないから。
# 今回の本題じゃないけどね。
επιστημηさん、シャノンさん
ありがとうございました。
解決といたします。
ツイート | ![]() |