c++で独自キャスト演算
独自キャスト方法は、
operator <組み込み型>() const{ return <値>; }
なので、double型の設定を追加したい場合は、
operator double() const{ return this->val; }
※「this->val」のところは適当に書いてます
【C言語】ポインタ
ポインタって分かりにくいですよね。。。
改めて自分の理解のためにメモ書きしていきたいと思います。
今日のお話
環境
対象言語
- c
メモ
int型、double型のように、ポインタ型がある。
ポインタ型にも
ポインタ(int)型:int *
やポインタ(double)型:double *
がある。
→型として理解すればOKの認識。
ポインタ型は変数のアドレスを保持する
1回作成した変数に対して、操作をしたい時に、アドレスに対して操作を行えばよいため、効率が良い。 →「正直使わなくても問題ないですよね?」と言われてしまうと、この段階では問題は発生しない。
#include <stdio.h> void AddNumber(int *value) { *value = *value + 100; // 直接対象のアドレスに対して値を加えている } int main() { int a = 100; AddNumber(&a); printf("%d\n", a); return 0; }
#include <stdio.h> int AddNumber(int value) // 仮引数が生成される時に新たにvalue変数が生成されている { value = value + 100; return value; } int main() { int a = 100; a = AddNumber(a); // 戻ってきた値を改めてaに代入 printf("%d\n", a); return 0; }
- ポインタが必要になるのは配列の場合で、生成した(or 引数で受け取った)値をアドレスを通じて戻さないといけない。
#include <stdio.h> #include <stdlib.h> int *AddNumber() { int *values = (int *)malloc(sizeof(int) * 100); for (int i = 0; i < 100; i++) { values[i] = 100; } return values; } int main() { // int a[100]; int *a; a = AddNumber(); for (int i = 0; i < 100; i++) { printf("No.%d: %d\n", i, a[i]); } return 0; }
関数から配列(値)返すことができない。 →ローカル変数は関数の中でのみ有効になるため
↓はNG(出力するとおかしな値になる)
#include <stdio.h> int *AddNumber() { int values[100]; for (int i = 0; i < 100; i++) { values[i] = 100; } return values; // returnした後にvaluesが解放されてしまう } int main() { // int a[100]; int *a; a = AddNumber(); for (int i = 0; i < 100; i++) { printf("No.%d: %d\n", i, a[i]); // 正しい値が出力されない } return 0; }
- 関数の引数は値渡しになるため
NULL
値を渡してローカル変数で設定しても 関数のスコープを抜けたときに解放されてしまう。 どうしてもやりたい場合は、ダブルポインターを使う。
#include <stdio.h> #include <stdlib.h> void AddNumber(int **value) { *value = (int *)malloc(sizeof(int)); **value = **value + 100; } int main() { int *a = NULL; AddNumber(&a); printf("%d\n", *a); return 0; }
- 配列の指定方法はどちらで同じ
- a[i] = 100;
- *(pa + i) = 200;
int a[10]; int *pa = a; // &a[0]と同じ for (int i; i < 10; i++) { a[i] = 100; *(pa + i) = 200; printf("No.%d: %d\n", i, *(pa + i)); }
- 関数の引数で配列を使う場合、以下は全てパターン1と同じ意味になる。 →どれで書いても同じなので、パターン1を使った方が無難そう
int SampleFunc(int *a); // パターン1 int SampleFunc(int a[]); // パターン2 int SampleFunc(int a[5]); // パターン3
- 下記は全て同じ結果になる。
int a[10]; printf("&a : %p\n", (void *)&a); printf("&a[0] : %p\n", (void *)&a[0]); printf("a : %p\n", (void *)a); printf("============\n"); for (int i = 0; i < 5; i++) { printf("%d : %p\n", i, (void *)&a[i]); } printf("============\n"); int *p = a; for (int i = 0; i < 5; i++) { printf("%d : %p\n", i, (void *)&p[i]); } printf("============\n"); // この形式で追加しても良いが型がint[10]へのポインタになる int(*pa)[10]; pa = &a; for (int i = 0; i < 5; i++) { // (int *)にキャストして、そこからポインタ演算でインクリメント printf("%d : %p\n", i, (void *)(((int *)pa) + i)); }
戯言
- ポインタもそうだけど、C言語に詳しくならないと。。。
【C++】コールバッククラスを作ってみた
コールバックを使ってみたかった。
あと、コールバック用のクラスも作ってみたかった。
という自分用のメモです。
今日のお話
環境
対象言語
プログラム
/** * @file task.cpp * @brief * @details * ■やってみたかったこと * ①外部から処理を設定する * ②処理の順番を決める * @date 2021-03-20 */ #include <iostream> #include <functional> #include <stdio.h> #include <time.h> /** * @brief std * @details */ using namespace std; /** * @brief タスク * @details */ class Task { private: function<void()> prepare = nullptr; function<int()> execute = nullptr; function<void()> postproc = nullptr; function<void(int)> success = nullptr; function<void()> error = nullptr; public: /** * @brief 準備処理 * @details * @param _prepare */ void onPrepare(function<void()> _prepare) { prepare = _prepare; } /** * @brief 実行処理 * @details * @param _execute */ void onExecute(function<int()> _execute) { execute = _execute; } /** * @brief 事後処理 * @details * @param _postproc */ void onPostproc(function<void()> _postproc) { postproc = _postproc; } /** * @brief 成功時の処理 * @details * @param _postproc */ void onSuccess(function<void(int)> _success) { success = _success; } /** * @brief 失敗時の処理 * @details * @param _postproc */ void onError(function<void()> _error) { error = _error; } /** * @brief 実行関数 * @details 設定されている処理を順に実行していく */ void Exec() { // 事前処理 prepare(); // 実行処理 try { // 実行 int res = execute(); // 成功 success(res); } catch (exception &ex) { // 失敗 error(); } // 後処理 postproc(); } }; /** * @brief 乱数 初期値 * @details 乱数の初期値設定関数 */ inline void InitRand() { srand((unsigned int)time(NULL)); } /** * @brief メイン関数 * @details * @return int */ int main() { // タスクインスタンス Task task = Task(); // 準備処理 task.onPrepare([]() { cout << "** prepare **" << endl; InitRand(); }); // 実行処理 task.onExecute([]() { cout << "exec..." << endl; // 乱数の発生 int res = rand(); if (res % 2 == 0) { throw exception(); } return res; }); // 事後処理 task.onPostproc([]() { cout << "** postproc **" << endl; }); // 成功時 task.onSuccess([](int res) { cout << "success : " + to_string(res) << endl; }); // 失敗時 task.onError([]() { cout << "error" << endl; }); // 実行 task.Exec(); return 0; }
気付き
function型というものがある。
関数を外部から注入することができるので、見通しをよくできそう。
戯言
- もう春ですね
【Bash】ダミーファイル作成 ( +ファイル加工 )
システム作っているとダミーファイルを作ることもありますね。
テストの時とかね。
めんどくさいことはシェルにやってもらおう!
今日のお話
環境
対象言語
10個のファイルを作りたい場合
コマンド
$ for i in $(seq 0 9) ; do echo Value = $i > $i.txt; done
メモ
- 0.txt ~ 9.txt までファイルが作られる
- 中身は「Value = xx」になる。
10MBのサイズのファイルを作成する
コマンド
$ dd if=/dev/zero of=dummy bs=10485760 count=1
メモ
- Linuxなら
bs
のところは10MBと書けばいいと思う。 if
はインプットするファイル名(今回はNULLで敷き詰めている)of
はアウトプットするファイル名
特定の文字を検索結果のファイルに挿入
コマンド
$ find . -name "*.txt" -print | while read LINE; do echo "add text" >> $LINE; done
メモ
- txtファイルで見つけ出したファイルに対して「add text」を追加
- while/forのセミコロンの位置が分からなくなるけど要するに
do xxx
なんだ。(今から〇〇しますよーみたいなね)
気付き
戯言
- whileとかforとかさらっと使えるとすごく時短になるよね。
- こんな時に使えます!みたいなものがいっぱいあると読んでて楽しくなりそうだなー。
【Linux】Findを使ったコマンド例
Findコマンドについてメモしておく。
結構使うことあるんだよな。。。
都度更新していこう。
今日のお話
環境
対象言語
サンプルフォルダ構成
━app● ┝.git● ┝src● ┃┝hoge.cpp ┃┝hoge.h ┝lib● ┝libsample.so ● : ディレクトリ
コマンド
- .git以外のフォルダの一覧
$ find app -name ".git" -type d -prune -o -type d -print
気付き
戯言
- 随時更新していこう。。。
- findはどんどん使って行きたい。
- xargsとかも使えるようにしていきたい。
【C++】カスタム例外と継承
カスタム例外を作りたくなりました。
さらにカスタム例外クラスを継承したくなりました。
なので試してみようと思います。
今日のお話
開発言語
やりたいこと
- 例外クラスのインスタンスを作る時にメッセージを設定できるようにしたい
- ↓みたいな階層構造にしたいと思いました。
exception:標準例外クラス
┗BaseException:カスタム例外クラス(親クラス)
┗SubException:カスタム例外クラス(子クラス)
サンプルソース
#include <iostream> using namespace std; // カスタム例外クラス(親クラス) class BaseException : public exception { public: BaseException(const string &msg) { message = msg; } char const *what() const noexcept { return message.c_str(); } private: string message; }; // カスタム例外クラス(子クラス) class SubException : public BaseException { public: SubException(string msg) : BaseException(msg) {} }; // サンプル関数 void SampleFunc() { try { throw SubException("aaa"); } catch (SubException subex) { cout << subex.what() << endl; throw; //ここで再スロー } } // メイン関数 int main() { try { SampleFunc(); } catch (BaseException bex) // SubExceptionも受け取れる { cout << bex.what() << endl; } return 0; }
気付き
- exceptionクラスはデフォルトではコンストラクタにメッセージを追加することができないみたいです。*1
SubException
のスローするとBaseException
でもキャッチすることができますね。(当たり前ですがw)- これで
SubException
に詳細エラーを書いて、BaseException
でもう少し全体的なエラーにすることができます。
戯言
exception
クラスにはデフォルトでメッセージを登録するようなことはできないみたいです。- 例外も階層化すればエラーがあった時にトレースが便利になると思うから、設計の時とかに意識して使っていけるようにしたいな。
*1:例外クラスとstd::exception:https://teratail.com/questions/79022
【CentOS7】C++でReflection ~RTTRライブラリのインストール~
C++でReflectionがしたい。。。
そんな時にGithubでRTTRと言うライブラリを見つけました。
今回は試行錯誤してインストールした方法を書いてみたいと思います。
注意事項
このインストール方法は公式の方法ではありません。
試行錯誤したらやっとライブラリが使えるようになったので、同じ悩みを抱えている人の参考になるかと思い書いてます。
公式インストール手順は、ちゃんと下記に載ってます。
https://www.rttr.org/doc/master/building_install_page.html
今日のお話
開発言語
- c++11
環境
インストール方法
必要なパッケージをインストール
root
ユーザで実行
# yum install -y gcc-c++ # yum install -y epel-release # yum install -y —enablerepo=epel cmake3
RTTRライブラリのビルドとインストール
root
ユーザで実行
# wget https://www.rttr.org/releases/rttr-0.9.6-src.tar.gz # tar zxvf rttr-0.9.6-src.tar.gz # mkdir build # cd build/ # cmake3 -DCMAKE_BUILD_TYPE=Release ../rttr-0.9.6/ # make # make install # cp -rp install/lib64/librttr_core.so /usr/lib64/ # cp -rp install/lib64/librttr_core.so.0.9.6 /usr/lib64/
RTTRライブラリを使ったcppファイルを作成
main.cpp *1
#include <iostream> #include <rttr/registration> static void f() { std::cout << "Hello World" << std::endl; } using namespace rttr; RTTR_REGISTRATION { using namespace rttr; registration::method("f", &f); } int main() { type::invoke("f", {}); } // outputs: "Hello World"
RTTRライブラリを使ってアプリをビルド
○ビルドコマンド
$ g++ -std=c++11 main.cpp -I./install/include -lrttr_core
最終的に↓みたいなディレクトリ構成です!
/usr/lib64 #共有ライブラリ ┣librttr_core.so ┗ librttr_core.so.0.9.6 /home/vagrant ┣rttr-0.9.6/ ┗build/ ┣main.cpp #作ったcppファイル ┗install/ ┗include/ #ヘッダー
気付き
- 共有ライブラリパス
/usr/lib64
にライブラリを配置することでgccコマンドでライブラリのパス指定が不要になる。 - ライブラリの指定は、
-L
でできるらしい。※今回はコンパイルが上手くいかなかったのであえてファイルをcpしました。 - ライブラリ名は「libxxx.so」となっている必要があり、gcc側でパラメータを指定する時は、「-lxxx」となる。(
lib
,.so
は不要になる)
戯言
*1:サンプルコードの出典元( 1行目の #include だけ追加してます) https://www.rttr.org/doc/master/register_hello_world_page.html