最終更新日時(UTC):
が更新

履歴 編集

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);  // 将来的な動作

関連項目

参照