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