std:: の標準ライブラリの代わりに y3c:: 以下のクラスを使うことで、例外がcatchされなかった場合や未定義動作の代わりにわかりやすいエラーメッセージとスタックトレースを表示します。 C++初心者におすすめです。
Linux, MacOS, Windows (MSVC, MinGW) で動作確認しています。 スタックトレースの取得と表示に関しては cpptrace ライブラリを使用しています。
例えば範囲外アクセス:
#include <y3c/array> // <- instead of #include <array>
int main() {
y3c::array<int, 5> a; // <- instead of std::array<int, 5>
a[100] = 42; // this would be undefined behavior, but...
}
↓
y3c-stl terminated: undefined behavior detected
at y3c::array::operator[](): attempted to access index 100, that is outside the bounds of size 5.
Stack trace (most recent call first):
#0 0x0000000104f6a16f in main at /Users/kou/projects/y3c-stl/build/../examples/array-operator.cc:5:5
3: int main() {
4: y3c::array<int, 5> a;
5: a[100] = 42;
6: }
Abort trap: 6
イテレータや参照、ポインタなどを雑に使っても大丈夫です。
(生参照や生ポインタはさすがに対策できないのでそれらと同等の y3c::wrap<T&>
, y3c::wrap<T*>
を用意しています)
#include <y3c/array>
#include <iostream>
int main() {
y3c::array<int, 5> a = {1, 2, 3, 4, 5};
y3c::array<int, 5>::iterator it = a.begin();
it += 10;
std::cout << *it << std::endl;
}
↓
y3c-stl terminated: undefined behavior detected
at y3c::array::iterator::operator*(): attempted to access index 10, that is outside the bounds of size 5.
Stack trace (most recent call first):
#0 0x0000000102929573 in main at /Users/kou/projects/y3c-stl/build/../examples/array-iter.cc:8:18
6: y3c::array<int, 5>::iterator it = a.begin();
7: it += 10;
8: std::cout << *it << std::endl;
9: }
Abort trap: 6
また、範囲外だけでなく寿命切れやnullptrアクセスなど他の未定義動作も対策済みです。
#include <y3c/array>
#include <iostream>
int main() {
y3c::ptr<int> p; // <- instead of int &p;
{
y3c::array<int, 5> a;
p = &a[3];
std::cout << *p << std::endl;
}
std::cout << *p << std::endl;
}
↓
0
y3c-stl terminated: undefined behavior detected
at y3c::ptr::operator*(): attempted to access the deleted value.
Stack trace (most recent call first):
#0 0x0000000100195337 in main at /Users/kou/projects/y3c-stl/build/../examples/array-ptr-local.cc:11:18
9: std::cout << *p << std::endl;
10: }
11: std::cout << *p << std::endl;
12: }
Abort trap: 6
Meson (>=0.56) をインストールしてください。
- Ubuntu:
pip install meson
またはsudo apt install meson
- MacOS:
brew install meson
- Windows MSVC: 公式サイト からダウンロードしてください。
- MSYS2:
pacboy -S meson
以下のコマンドでy3c-stlと依存ライブラリをビルド、インストールできます。
git clone https://github.com/na-trium-144/y3c-stl
cd y3c-stl
meson setup build
meson install -Cbuild --skip-subprojects
Windowsの場合は meson setup 時の引数で -Dprefix=C:/Users/hoge/y3c
などとインストール先を指定するとよいです。
Linux,Macの場合は何も指定せずデフォルトのまま (/usr/local
など) がおすすめです。
また、Windows MSVC の場合はdebugビルド(デフォルト)とreleaseビルド(meson setup 時に -Dbuildtype=release
を指定)の両方をインストールする必要があります。
- y3c-stlは y3c という名前の共有ライブラリとなっているのでそれをリンクするだけでokです。
- ただしWindowsのMSVCでdebugビルドの場合は y3cd という名前になります。
- また、Windowsの場合はy3cのdllファイル(インストール場所のbinディレクトリにあります)を実行ファイルと同じディレクトリにコピーするか、PATHを通す必要があります。
- Linux,Macでインストール先がデフォルトの場合は
-ly3c
を渡せばよいです。- インストール先を変更している場合は
-I/path/to/y3c/include -L/path/to/y3c/lib -ly3c
などとパスも指定する必要があります。
- インストール先を変更している場合は
- Windows MSVCの場合は
/IC:\path\to\y3c\include
と/libpath:C:\path\to\y3c\lib
でパスを指定し、y3c.lib
(releaseビルドの場合) またはy3cd.lib
(debugビルドの場合) を渡せば良いです。 両方渡せば確実です(内部でnamespaceを分けているので混ぜても問題ありません)。
- コンパイラの引数に
$(pkg-config --cflags --libs y3c)
を渡せば良いです。- インストール先を変更している場合は
PKG_CONFIG_PATH
環境変数に/path/to/y3c/lib/pkgconfig
などを追加する必要があります。
- インストール先を変更している場合は
find_package(y3c REQUIRED)
target_link_libraries(your_target y3c::y3c)
y3c_dep = dependency('y3c')
executable('your_target', ..., dependencies: y3c_dep)
- std:: 以下の各種クラスの代わりに y3c:: 以下のクラスで置き換えることで、よくある例外や未定義動作についていろいろな追加のチェックが実行時に行われます。
- さらに
int
などのクラスでない変数についてはy3c::wrap<int>
、参照int&
→y3c::wrap<int&>
、 生ポインタint*
→y3c::wrap<int*>
で置き換えることで、nullptrや範囲外へのアクセス、また寿命が切れた変数へのアクセスかどうかをチェックすることができます。 - いずれも
y3c::unwrap()
(またはunwrap()
) 関数を使うことで対応する std:: 以下のクラス、wrap元の型(の参照)に復元できます。 (unwrap後はチェックが行われませんが)
- さらに
- 例外を投げるパターンの場合は (例えば
std::array::at()
→std::out_of_range
)、 それがcatchされなかった場合にわかりやすいエラーメッセージとスタックトレースを表示します。- 通常の例外と同じようにcatchすることも可能です。(その場合は何も表示されません)
- catchする場合はstdクラスの場合と同様に std:: の例外クラスでcatchできます。
継承関係もそのままです。
(例えば
std::out_of_range
はstd::logic_error
,std::exception
としてもcatchできます。)
- 未定義動作を起こすパターンの場合、エラーメッセージとスタックトレースを表示した後 abort() します。
- スタックトレースの表示処理は
std::set_terminate()
に登録したハンドラーの中で行っているため、 y3c:: のラッパークラス以外が投げた標準のexceptionや、直接std::terminate()
を呼び出した場合もスタックトレースが表示できる場合があります。
- nullptrアクセスのチェック
- 範囲外アクセスのチェック
- 寿命が切れた値へのアクセスのチェック
ただしいずれもチェックされる条件として生ポインタや参照の代わりに y3c::ptr
, y3c::wrap_ref
などを使用することに加えて、
アクセスする対象も y3c:: のクラスまたは y3c::wrap
でラップされている必要があります
todo: doxygenのドキュメントを作りそれへのリンクにするとか
#include <y3c/wrap>
(y3c独自のユーティリティ関数、STLのクラスに属さないものなど)y3c::link()
y3c::unwrap(y3c::wrap<T>)
y3c::wrap<T>
←T
y3c::wrap_ref<T>
=y3c::wrap<T&>
y3c::const_wrap_ref<T>
=y3c::wrap<const T&>
y3c::ptr<T>
=y3c::wrap<T*>
y3c::const_ptr<T>
=y3c::wrap<const T*>
y3c::ptr_const<T>
=const y3c::wrap<T*>
y3c::const_ptr_const<T>
=const y3c::wrap<const T*>
#include <y3c/array>
y3c::array<T, N>
←std::array<T, N>
#include <y3c/memory>
y3c::shared_ptr<T>
←std::shared_ptr<T>
y3c::make_shared<T>()
←std::make_shared<T>()
y3c-stlはMITライセンスの下で公開されています。