最終更新日時(UTC): 2025年04月24日 03時21分52秒
Akira Takahashi が更新

履歴 編集

# std::initializer_listの配列を静的記憶域に配置する [P2752R3](C++26)

このページはC++26に採用される見込みの言語機能の変更を解説しています。

のちのC++規格でさらに変更される場合があるため関連項目を参照してください。

## 概要

C++11で導入された`std::initializer_list`は、自作クラスで組み込み配列のような配列初期化をする構文であるが、そのメモリとしてはスタック上に配置されていた。

    std::vector<int> v = {1, 2, 3};

    // 以下と等価：
    const int __a[] = {1, 2, 3};
    std::vector<int> v(__a, __a + 3);

C++26では、プリプロセス時にファイル読み込む`#embed`機能が導入されることもあり、スタックオーバーフローのリスクがあった。

    std::vector<char> v = {
      #embed "2mb-image.png"
    };

このため、C++26では、定数値のみ、かつ`mutable`に保持しない`std::initializer_list`は、静的記憶域に配置されるようになる。

    void f(std::initializer_list<double> il);

    void g(float x) {
      f({1, x, 3});

      // 変数を含むため、静的記憶域には保持されない。
      // 以下と等価：
      // const double __a[3] = {double{1}, double{x}, double{3}};
      // f(std::initializer_list<double>(__a, __a+3));
    }

    void h() {
      f({1, 2, 3});

      // 定数のみであるため、静的記憶域に保持される。
      // 以下と等価：
      // static constexpr double __b[3] = {double{1}, double{2}, double{3}};
      // f(std::initializer_list<double>(__b, __b+3));
    }

    struct A {
      mutable int i;
    };

    void q(std::initializer_list<A>);

    void r() {
      q({A{1}, A{2}, A{3}});

      // mutableにするため、静的記憶域に保持される。
      // 以下と等価：
      // const A __c[3] = {A{1}, A{2}, A{3}};
      // q(std::initializer_list<A>(__c, __c+3));
    }

将来的に、静的記憶域に配置される配列は、共有される可能性がある。この動作のために、共有で予期しない問題が起きる`mutable`は共有から除外される。

    std::initializer_list<int> i1 = {1,2,3,4,5};
    std::initializer_list<int> i2 = {2,3,4};
    PERMIT(i1.begin() == i2.begin() + 1);  // 将来的な動作

## 関連項目

- C++11 初期化子リスト
- C++26 ファイルを読み込む`#embed`命令を追加

## 参照

- P2752R3 Static storage for braced initializers