Author Archives: admin

Visual Studio Codeでwslのアプリをデバッグ

忘備録。Visual Studio CodeはWindows側で実行している。

wslでアプリのソースとバイナリを用意

ここではubuntuを使っている。

/etc/apt/sources.listでソースパッケージを有効に

デフォルトではソースパッケージが無効になっているので、/etc/apt/sources.list
を開いて、deb-srcで始まる行のコメントを削除する。

fortuneで試す

fortuneというコマンドラインアプリがあるので、これのソースコードと取得し、wsl内でビルドしておく。ディレクトリは/mnt/内(Windowsとwslで両方から操作できる)で行うこと。

これでソースが取得できたので、これをデバッグビルドする。このアプリの場合はMakefileがついていて’make debug’ができるようなので実行する。

が、これがエラーになるのでCFLAGSを指定してビルドした。

これでwsl側の準備ができた。

VSCodeを開く

VSCodeでフォルダY:\work\fortune\fortune-mod-1.99.1を開き、デバッグ環境C++(GDB/LLDB)でlaunch.jsonを開き以下を入力

これでデバッグできた。
VSCodeでデバッグ

h265

h265

HEVC(High Efficiency Video Coding)はMPEGによって開発された。
最大効率でAVC(H264)の2倍。動画のサイズが半分になる。
fourccはhvc1またはhev1

シンプルな例

CRF(Constant Rate Factor)

サイズを犠牲にして品率を高める割合。低いほうが品質が高い。デフォルトは28、0から51まで指定可能
0だとロスレスだけどファイルサイズが大きくなる、51が最悪だけどファイルサイズが小さい。

プリセット

圧縮効率を指定してエンコード時間を調節する機能。以下のうちの一つを指定。
superfast, veryfast, faster, fast, medium, slow, slower, veryslow

ex)

実際にこれをやってもサイズは小さくならなかった。なぜ?

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

unique_ptrの基本とカスタムdelete

コード例

基本

unique_ptrは渡されたポインタの所有権を保持する。つまりこのポインタを解放するのはunique_ptrの役割である。ポインタが破棄されるのはunique_ptrが破棄される時かreset()によって他のポインタがセットされる時である。よってget()で取得したポインタを破棄したり、他のスマートポインタに渡してはいけない。

std::move

unique_ptrをunique_prtにコピーというか移動するにはstd::moveを使わなくてはならない。

カスタムデリート

unique_ptrの第2テンプレート引数にはデリーターを指定する。この関数は破棄される際にポインタが渡される。デフォルトはdeleteなので作成時にnewで作ったオブジェクトを渡す。しかしnewで作れないオブジェクトはたくさんあるのでコード例のようにカスタムデリーターを指定する。

std::function

カスタムデリーターはポインタ1つを引数に取る関数オブジェクトのを指定しなければならない。呼び出し規約がデフォルトと違う場合はそれも指定しないといけないのでややこしい。この場合はstd::functionを使えば呼び出し規約を気にしなくてもいい。

開放関数が引数を2つ取るなどの場合はラムダやファンクタを指定することになる。

ソースコード

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