1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

領域確保とコンストラクタが呼ばれるタイミング

Posted at

はじめに

少し考えれば当たり前かもしれませんが、以下のコードはどのような挙動をするでしょうか?

sample
struct A {
    A() { std::cerr << "constructor" << std::endl; }
    std::array<char,99999999> buf;
};

int main() {
    std::cerr << "hoge" << std::endl;
    {
        A a;
    }
    std::cerr << "fuga" << std::endl;
}

g++ sample.cpp -O0

一見問題ないコードに見えます。実際、c++の文法的には問題なかったはずです。が、std::arrayで確保している領域が莫大なので、実行時はスタックを使い果たして何かしらのエラーが起きるなりして終了するでしょう。(最適化によってA aの存在が消滅させられる可能性はあります)

問題は、どのような出力が得られるかです。エラーになるのはスタックに積まれるときなので、コンストラクタは実行されないはずです。ということはhogeが出力されるのでしょうか?

しかし結果は、何も出力されませんでした。

私の誤解

お恥ずかしい限りなのですが、c++においてローカル変数の領域が確保されるのはスコープに入った時だと思っていました。これが正しければ、hogeが出力されます。

この結果に納得いかなかった私は、なんとかしてhogeを出力しようと試みました。

試行錯誤した結果

無理でした。というかそのような挙動になる理由がないです。上記の挙動は私が「領域の確保」を勘違いしていただけと思われます。

冷静に考えたらメモリ領域のサイズが分かっているのに複数回に分けてスタックに積む必要がありません。

また、アセンブリを覗いて気が付いたのですが、通常はスタック周りの保護のために関数呼び出し前後でコードが挿入されています。なので無茶なスタックを確保するコードを書いたら、main関数に入る前に落ちている可能性が高いです。

再現するには関数を使ってスタックを積みなおす必要ばあります。

void func() {
    std::cerr << "called" << std::endl;
    A a;
}
int main() {
    std::cout << "hoge" << std::endl;
    func();
}

ちなみにこの場合、hogeが出力されてcalledは出力されません。実行時エラーのデバッグ時に、このように関数呼び出しで落ちていた場合はスタック周りを疑ってみるといいかもしれません。

正しい挙動は?

おそらくスタック周りの動作は実装依存だと思われます。(詳しい方がいたら教えてください)
コンストラクタは記述した通りに呼ばれています。

固定長だからとむやみにstd::arrayを使うのは考えものですね。

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?