読者です 読者をやめる 読者になる 読者になる

とくにあぶなくないRiSKのブログ

危ないRiSKのブログだったかもしれない。本当はRiSKだけどググラビリティとか取得できるIDの都合でsscriskも使ったり。

{ } での初期化

{ } での初期化で,どのコンストラクタが呼ばれるのか実験。

#include<iostream>
#include<initializer_list>

int main(){
 { // #1
  struct s
  {
   int member;
  };
  s test{1};
  std::cout << test.member << std::endl;
 }
 { // #2
  struct s
  {
   int member;
   s(int){std::cout << "s(int)\n";}
  };
  s test{1};
  std::cout << test.member << std::endl;
  s test2(1);
  std::cout << test2.member << std::endl;
 }
 { // #3
  struct s
  {
   int member;
   s(std::initializer_list<int>){std::cout << "s(std::initializer_list<int>)\n";}
  };
  s test{1};
  std::cout << test.member << std::endl;
 }
 { // #4
  struct s
  {
   int member;
   s(int){std::cout << "s(int)\n";}
   s(std::initializer_list<int>){std::cout << "s(std::initializer_list<int>)\n";}
  };
  s test{1};
  std::cout << test.member << std::endl;
  s test2(1);
  std::cout << test2.member << std::endl;
 }
}

実行結果:

1
s(int)
2008809472
s(int)
4200041
s(std::initializer_list<int>)
26
s(std::initializer_list<int>)
2008968564
s(int)
4230600

この実験では = を省いている。 s test = {1}; ではなく, s test{1}; のようにしている。どちらも多分同じ。また,この実験で,1と出力されればメンバは初期化されているし,変な値が出力されればメンバは初期化されていないことが分かる。
#1 はCで言ういわゆる構造体の初期化みたいな感じ。コンストラクタを書くことなく member が初期化される。
#2 は通常のコンストラクタだけを書いている。この場合,コンストラクタの引数に対応する値が入る。member が自動的に初期化されることはないので,今までどおり受け取った引数でメンバを自分で初期化するコードを書く。
#3 はinitializer_listを受け取るコンストラクタだけを書いている。この場合も member が自動的に初期化されることはないので,initializer_list の要素でメンバを初期化するコードを書く。
#4 は通常のコンストラクタと initializer_list を受け取るコンストラクタの両方を書いている。この場合も member が自動的に初期化されることはないので,両方のコンストラクタにそれぞれメンバを初期化するコードを書く。test{1} のケースは initializer_list にマッチし, test2(1) のケースは initializer_list ではないほうにマッチする。

思いごと・分からないこと

  • 多分,#2 のケースは利便性のために特別なんだと思う。
  • {} と initializer_list は厳密には別物なんじゃないかなぁ。うん,別物だね。
  • initializer_list は何でコピーで受け取るのか分かってない。ドラフト見ると std::vector なんかもinitializer_list はコピーで受け取ってる。 const & とか && で受け取ると効率悪いの?

追記:空の { }

#include<iostream>
#include<initializer_list>

int main(){
 struct s
  {
   int member;
   s(){std::cout << "s()\n";}
   s(std::initializer_list<int>){std::cout << "s(std::initializer_list<int>)\n";}
  };
  s test{};
  std::cout << test.member << std::endl;
}

実行結果:

s()
4230544

空の{}の場合はデフォルトコンストラクタにマッチするみたいですね。

追記2:空の{}を無理やり(?)渡す

ctor({}) とすれば,{} を渡せる模様。誰がうれしいのかは知らない。

#include<iostream>
#include<initializer_list>

int main(){
 struct s
 {
  int member;
  s(){std::cout << "s()\n";}
  s(std::initializer_list<int>){std::cout << "s(std::initializer_list<int>)\n";}
 };
 s test({});
 std::cout << test.member << std::endl;
}

実行結果:

s(std::initializer_list<int>)
8465328

それにしてもぐじゃぐじゃなエントリだ。実験貼り付けただけだしね…。