Qtのマクロ

Q_LIKELY Q_UNLIKELY

コンパイラに分岐予測最適化を提供するためのマクロ。ifの中で使い、trueになりそうなときはQ_LIKELY、falseになりそうなときはQ_UNLIKELYをつかう。Visual Studioコンパイラだと特に何もしないが、gccだと__builtin_expectに展開される。

Q_UNREACHABLE

絶対に到達しない場所に記述する。switch文ですべてのenumをcaseに書かないと警告が出る場合にこれを置いておく。

Q_UNUSED

関数の引数で使わないものを書いておくと警告が出なくなる。関数の引数の変数を消してもいい。

Q_ASSERT Q_ASSERT_X

実行時にtrueでなければならない式を記述してデバッグ時にエラーが出ないことを確認する。
_Xの方は警告文をいろいろ書ける。

Q_ASSUME

式がtrueであることをコンパイルに教えて最適化に役立てる。falseを指定すると、Q_UNREACHABLEと同じになる。

qDebug()

デバッグ出力する。

std::tieによる< (less)

std::mapなどで自作のクラスをキーにする場合、そのクラスはoperator<を定義していなければならない。クラスにメンバーが1つしかない場合は、それを比較するだけで簡単なのだが、2つ以上あるときは少し難しくなる。例えばメンバーa,bがある場合、以下のように書けない。

以下のようなoperator<検証プログラムを書くとassertに引っかかる。

例えば
C(1,6) < C(7,0)

1 < 7 && 6 < 0 で
false

逆にすると
C(7,0) < C(1,6)
7 < 1 && 0 < 6 で
両方falseになってしまう。

ちゃんと書くと以下のようになる。

この書き方だと3つになった場合分けがわからなくなるので、std::tieを使ってスマートに書ける。

アルゴリズムとしては==の代わりに !< を使って1つずつ比較していく。

このような比較はlexicographical_compareといって、イテレータを渡して実現することもできる。このコードでイテレータを渡すのは強引だが以下のようになる。

ソースコード

C++のstd::thread基本

スレッドでHello World!

スレッドに値を渡す(int)

スレッドに値を渡す(class)

実行結果

スレッドで実行しているので改行が合わない。がコンストラクタは以下のように呼ばれている。ユニバーサル参照のコンストラクタしか呼ばれていない。

Ideone

std::threadは基本的な機能しか提供していないようで高度なことはできないようだ。例えばスレッドを開始しなかったり、スタック領域をしていしたり、スレッドをKILLしたり、ただnativehandleで処理系依存のスレッドハンドルが取得できるのでKILLくらいならできる。スレッド関数の戻り値には意味がない。スレッドから値を取得したい場合は引数経由で行う。

KILLしてみたコード

上のコードはうまく動かなくなる。coutがおかしくなってしまうのだと思われる。

というわけであんまり使えなそうである。スレッド関数はあくまでも計算とかを実行し、入出力に使うのは基本的に良くない。

ソースコード

Qtでプリコンパイルヘッダを使う

C++のコンパイルは時間がかかる。ソースファイルでインクルードされている全てのファイルをパースしなければならないため。C++ではヘッダに実装を書く事も多くなりさらに重くなっている。

プリコンパイルヘッダとはソースコードの共通の最初の部分をあらかじめコンパイルしておきそれを共通で利用する方法。最初の部分は共通でないとならないので、その共通の部分を1つのヘッダファイルにしておき、ソースコードではそれをファイルの先頭でインクルードすることで利用する。経験上ではMicrosoftclコンパイラだととても早くなる。

この共通の部分には普通は他のライブラリのヘッダファイル、例えばWindows.hstringvectorなどの標準ライブラリなど自分で編集しないファイルをおく。

Visual Studioでソリューションを作成すると自動でこのプリコンパイルをやってくれるが、QtのQt Creatorなどではやってくれないのでその方法。

*.proファイルにPRECOMPILED_HEADERを追加

以下の行を*.proファイルに追加する。

stable.hの名前は好きでいいはず。Visual StudioなどではStdAfx.hpch.hに相当する。

stable.hを新規にプロジェクトに追加

stable.hを新規にプロジェクトに追加してそこに共通の#includeを書く、QtなのでQで始まるファイルが多くなると思われる。ここではソースファイル郡から検索する方法を紹介。

コマンドで#includeを見つける

以下のコマンドはsrc/以下から全てのファイルを検索してインクルードを見つける。

-hはファイル名を表示しないオプション。このコマンドで表示されたものをstable.hに書く。以下は例。

準備完了

これでプリコンパイルの準備は出来た。Visual Studioとは違いソースコードでstable.hをインクルードしなくても良い。勝手にやってくれるようだ。ソースコード中の今までのインクルードは別にそのままでも良い、というかそのままにしておくべき。プリコンパイルを利用できない環境だと困るため。通常はすでにインクルードされているものは除外するように記述されているので問題ない。

ビルドをして早くなったか確認する。

パスがネットワークドライブにあるか判定する。

Win32API

PathIsNetworkPath

このAPIを使うのが一番簡単。shlwapi.hshlwapi.libが必要。

GetDriveTypeA

これが最も原始的やり方だと思う。kernel32にある。

.NETの場合

System::IO::DriveTypeを使う。

C++/CLIの例

C++ 関数と関数ポインタの違い

関数と関数ポインタは配列とポインタの関連に似ている。

配列とポインタ

配列は関数の引数になるとポインタに変わる。下の2つの関数abは同じ。

このように配列がポインタに変わる動作をdecayと呼ぶ。

関数と関数ポインタ

下の2つの関数abも同くdecayする。

参照はdecayしない

関数bは配列のサイズも合ってないとエラーになる。

結論

値渡しはdecayするが参照渡しはdecayしない。これにtemplateが絡むとすごく複雑になる。

ソース

https://github.com/ambiesoft/blogprogs/tree/master/5216