C++11」カテゴリーアーカイブ

ICC17.0の変数テンプレートが少〜し変よ〜

ICC17.0が出たのでさっそくアップデートしました。

  • Support C++14 variable templates (N3651)

となってるのでワクテカで変数テンプレートを試してみたわけですがちょっとおかしい。

とりあえずconstexprな変数テンプレートのコンパイルは通る。

だがしかし、constexpr な変数テンプレートを特殊化するとコンパイルエラーになる。

これ、ClangやMSVCではコンパイル通るけど、ICC17.0では「a constexpr variable declaration must be a definition」というエラーが出る。

変数テンプレートのconstexprを取り除いて

ってするとICC17.0でもコンパイル通る。。。。 これってICCの変数テンプレートの実装ミスだよなあ。。。。。

std::make_shared にまつわるエトセトラ

C++11が世に出てもう5年経つので世の中のC++erさんにはもう常識なハナシかとは思いますがロートルおじさんは最近初めて知りました。結構ビックリ。

std::shared_ptr( new T(args…) );
std::make_shared( args… );

make_sharedはてっきり記述を楽するだけのものかと思ってたら、オブジェクトと管理用のメモリ領域を一体で確保してくれるとのこと。
一方上のようにフツーにnewしたものからshared_ptrを作成すると、オブジェクトのメモリと管理領域のメモリがそれぞれ別々に確保される。

C++プログラマーよ!std::make_sharedを安易に使うべからず! : 株式会社CFlatの明後日スタイルのブログ
make_shared で確保されたメモリ領域は,それを参照する weak_ptr が無くならない限り解放されない : 野良C++erの雑記帳

・管理領域を一体で確保するからメモリの割り当て回数が少なくて済む。その分速い
・make_sharedが管理領域をまとめて独自にメモリを確保するのでクラスのoperator new/deleteが呼ばれない
・make_sharedの中からオブジェクトを構築するのでpublicでないコンストラクタを呼び出す手段がない
・オブジェクトを指すshared_ptrが全てなくなりdesutructされた後にまだそのオブジェクトを指すweak_ptrが残っている場合、管理領域を残す必要があるためにそれと一緒に確保された(destructされた後の)オブジェクトのメモリ領域が残ってしまう。そのオブジェクトを指すweak_ptrも全部無くなれば解放される。

うーん、make_sharedを使うか使わないか、結構意識しないといけないですねコレ。。。

C99の指示付き初期化子をC++で使っちゃっても良いのだろうか

C99の指示付き初期化子、便利ですよね。
でもC++11/14ではこれ定義されてない。

定義されてないんだけど、ClangなんかではC++と混ぜてフツーに使えてしまう。例えばこんな。

構造体メンバの初期化記法(構造体定義に直に初期値を記述)はC++11。そんで a の指示付き初期化リストの記述はC99。これで a は typeが0、valueが10 で初期化される。この書き方だと以下の利点がある。

・どのメンバをどの値で初期化するのかが判りやすい (C99)
・初期化の値の順番を気にしないで済む (C99)
・初期化で記述しなかったメンバはデフォルト値が設定される (C++11)

便利なんです。便利なんですが、Clangではコンパイル通るけど厳密にはアウトな書き方。(たぶん)

これが便利なのは例えば、「引数が沢山あって、でもどれもデフォルト値がある関数」。
C++の関数のデフォルト値は途中の引数だけ省略ってのができないのだけれど、引数を構造体でまとめてしまえば上記の方法で任意の引数(メンバ)だけを省略できるようになる。

こうすると、
・引数の値に名前を付けられて判りやすい
・引数の順番を気にせずに済む
・任意の引数を省略してconstexprなデフォルト値で初期化できる
のだ。

でも前述の通りC++規格的によろしくない。


追記:
インテルコンパイラ16.0ではやはりというか怒られる/(^o^)\
インテルコンパイラはC99オプションとC++11オプションを同時に有効にできないんだよな〜