世の中には怖いもの知らずというか、とんでもないコードを書く人たちがいます。例えば、
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
struct foo { std::string str; int a; int b; foo() { std::memset(this, 0, sizeof(*this)); } }; |
のようなコードです。さすがにこれはクラッシュする可能性が高いので、実行させてみれば間違いに気付くことでしょう。しかし、こんなのはどうでしょうか?
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
struct bar { std::pair<long, double> x; int a; int b; bar() { std::memset(this, 0, sizeof(*this)); } }; |
これだと動いてしまう処理系のほうが多そうです。std::pairのようなクラスをstd::memsetでゼロクリアするのはもちろん反則ですので未定義の動作になるわけですが、たまたま動いてしまうわけです。
では、std::stringやstd::pairのようなクラスを一切メンバに持たない、すなわちC互換型だけをメンバに持つような構造体であればコンストラクタでこのようなゼロクリアを行ってもよいのでしょうか?
そんなはずはありませんね。明示的なコンストラクタを定義した時点で、その構造体はもはやC互換構造体ではなくなります。C互換型ではないオブジェクトをstd::memsetでクリアすることはできません。多くの場合は動くかもしれませんが、それはあくまでもたまたまです。メンバの構成が変更されれば実害が出ることも十分考えられるので、こんなコードを書くのは避けるべきです。

![[迷信] 'A'~'Z'の値は連続している](https://www.kijineko.co.jp/wp-content/uploads/2021/05/2120715_s.jpg)
![[迷信] sizeofは定数式](https://www.kijineko.co.jp/wp-content/uploads/2021/06/4882007_s.jpg)
![[迷信] とりあえずmemsetで初期化](https://www.kijineko.co.jp/wp-content/uploads/2021/06/1322157_s.jpg)
![[迷信] setjmpマクロの返却値は変数に代入できる](https://www.kijineko.co.jp/wp-content/uploads/2021/06/4225767_s.jpg)
![[迷信] アルゴリズム関数内で関数オブジェクトはコピーされない](https://www.kijineko.co.jp/wp-content/uploads/2021/06/4845189_s.jpg)
![[迷信] double の出力書式は"%lf"](https://www.kijineko.co.jp/wp-content/uploads/2021/05/4950885_s.jpg)