まずB.G-STATIONとは何ぞや

B.G-STATION Advent Calendar 2017 1日目です。
adventar.org

まずは何ぞやって話です

まあ、B.G-STATIONは、僕が以前から運営していたというか運営しているサイトであり、同人個人サークル名でもあります。
B.G-STATION
車輪のx発明 ~B.G's Blog~

代表は僕であり、メンバーも僕だけですね。
(ちなみに、コミケでうちのスペースにもう一人座ってることがありますが、小学校からの友人でサーチケ代わりに午後店番とかやってもらってるのです。)

ホームページB.G-STATIONの誕生

高校の時に、科学部物理班という部活に入りました。
当時、コンピュータ教室が無かったのですが、理科講義室からPCの音が聞こえてました。
顧問の先生はロボット製作をしてて、僕らもそれをやってたこともあるのですが、先輩達は改造PC9821αにVisualBasic6を入れてゲームを作っていました。
それがプログラミングとの出会いでした。
僕もVB6+Win32でゲームを作ろうとしていましたが、割とすぐ挫折しました。
そして当時、家でCATVを導入したことで、インターネットができるようになりました。
ホームページスペースで最初に作ったホームページが初代のB.G-STATIONです。

B.G-STATION

これは初代じゃないですが、現存しているサイト・・・。ジオシティーズだから三代目かな・・・。
描いたイラストや作ったゲームを載せる予定でした。
イラストは載せましたが、ゲームは完成することがなかったので載せることはありませんでした。

同人ソフトサークルB.G-STATIONの設立

大学に入学した後、ゲーム製作関係のサークルに入りたくて、気になっていたAmusementMakers(以下AMと略します。)に入りました。

Amusement Makers

当時、東方紅魔郷とかでZUNさんとかが話題になり始めてた頃でした。
しかし、僕自身、東方シリーズは全く知らなかったし、AM出身とは全く知りませんでした。
また、TYPE-MOON月姫とか、葉鍵とか、ちょっとあとですがひぐらしがまだフリーウェアだった時代でもあります。

AMではノベル班に所属していました。
未来の描き方という同人ゲームがあったのですが、
ごく初期に背景を担当していました。というか正確にはする予定でした。
未来の描き方 - Google 検索
グラフィックを担当したのがいまや有名イラストレーターのカ〇トクさんで、彼のあまりのレベルの高さにレベルの低い僕が降りたというか降ろされたというかいろいろあってやることがなくなりました。
画力アップも兼ねて漫研にも入っていました。

並行して個人でゲーム作ってコミケで頒布しようとC66からコミケに申し込み始めました。
それが同人サークルとしてのB.G-STATIONです。

その後

C++ + DirectXでゲームを作り始めたのですが、挫折の連続・・・。
現在まで完成したものはありません・・・。
ああ・・・ダメすぎる人生・・・orz

卒業後も会社で忙しくしている間に、時代はC++ + DirectXからC# + Unityに・・・。
でもWin32APIにこだわりすぎてすっかり取り残されてしまいました。

同人誌を作ることもありました。いや、あの聖痕のクェイサー本は本当に黒歴史というか・・・。

そんな中、WindowsMobileからWindowsPhoneにハマり、廃れ・・・。

これから

そして今、また新たなスタイルでこのサークル及びサイトをやってるわけです。
どんなスタイルで何するのかって?
それを次回から書いていきます。

shared_ptr

shared_ptrは、C++11で導入されたスマートポインタの一種で、リソースの所有権は複数のポインタで共有できる。
いくつのポインタから参照されているかを参照カウンタというもので数えていて、どれからも参照されていないとき、リソースが解放される。

shared_ptr - cpprefjp C++日本語リファレンス

p1.use_countでp1の参照カウンタが見えるので、それで確認する。

shared_ptrのp1を同じくshared_ptrのp2に代入するとどうなるか。

今度は、ブロックの中にshared_ptrのp3を定義し、p1をp3に代入、さらにp2の値を変更。

ここまでの参照カウンタを確認してみる。

p1.resetでp1の所有権を放棄。p2が残るので、値と参照カウンタを出力。

$ vi main.cpp 
$ g++ -o main main.cpp test.cpp -std=c++11
$ ./main 
class_test::class_test(10)
x_ = 10
p1.use_count() = 1

x_ = 10
p1.use_count() = 2
x_ = 10
p2.use_count() = 2

x_ = 20
p1.use_count() = 3
x_ = 20
p2.use_count() = 3
x_ = 20
p3.use_count() = 3

p1.use_count() = 2
p2.use_count() = 2

x_ = 20
p2.use_count() = 1
class_test::~class_test()
$

p1だけだと参照カウンタは1。
p2に代入で参照カウンタは2。
p3にもp1を代入すると参照カウンタは3に、p2に値20をセットすると、同じものを参照してるのですべての値が20に。
ブロックを抜けたら、p3は参照されなくなるので、参照カウンタは2に減る。
p1の所有権が放棄されると、参照してるのはp2のみなので、参照カウンタは1。

Sample/cpp/shared_ptr/shared_ptr/src/shared_ptr at master · bg1bgst333/Sample · GitHub

unique_ptr

unique_ptrは、C++11で導入されたスマートポインタの一種で、とあるunique_ptrが指すリソースの所有権は1つのポインタしか持つことができない(現在はそのunique_ptrのみが持つ)という特徴がある。

unique_ptr - cpprefjp C++日本語リファレンス

test.hで、

test.cppで、

となるclass_testを定義する。

main.cppでは、

new class_test(10)で生成したポインタをすぐunique_ptrのp1の初期化に渡す。
スマートポインタの特徴として、メモリリソースの解放はスマートポインタがやってくれるので、deleteが無くても気にしなくていい。
あとは、p1はポインタのように扱うことができる。
そして、std::moveでunique_ptrのp2にムーブした時どうなるだろうか。

$ vi main.cpp 
$ g++ -o main main.cpp test.cpp -std=c++11
$ ./main 
class_test::class_test(10)
x_ = 10
x_ = 10
p1 is false!
class_test::~class_test()
$

p1自身がリソースを持っているかを判定できるので、ここでfalseになるということはp1にリソースはなく、p2に移ったということがわかる。
つまり、リソースは唯一である。

Sample/cpp/unique_ptr/unique_ptr/src/unique_ptr at master · bg1bgst333/Sample · GitHub

ノンタイプテンプレートパラメータ

本来、型を指定するのが、テンプレートのパラメータ部分だが、型以外のモノを指定することもできる。

テンプレート仮引数 | Programming Place Plus C++編【言語解説】 第22章

array.hで、

array_の型はTになっていて、テンプレートパラメータで型を指定する。
一方で、array_の添字の要素数の部分はNになっていて、これもテンプレートパラメータでintなのでこの場合は整数を指定する。

main.cppでは、

こんな感じでテンプレートパラメータを指定する。

$ vi main.cpp 
$ g++ main.cpp -o main
$ ./main 
set range error!
ary.get(0) = 10
ary.get(1) = 20
ary.get(2) = 30
ary.get(3) = 40
ary.get(4) = 50
get range error!
ary.get(5) = -1
$

確かに要素数は5である。

Sample/cpp/nontype_template_parameter/nontype_template_parameter/src/nontype_template_parameter at master · bg1bgst333/Sample · GitHub

decltype

decltypeを使うと、指定された式の型を取得することができる。

decltype - cpprefjp C++日本語リファレンス

decltypeで取得した型で変数宣言など、一般の型と同じように使える。

前回の、後置戻り値型に使ったり、

変数宣言に使ったり、

参照も判断できる。

$ vi decltype.cpp 
$ g++ decltype.cpp -o decltype -std=c++11
$ ./decltype 
str1 = ABC
typeid(str2).name() = NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
str2 = XYZ
ref2 = XYZ
str1 = XXX
str2 = YYY

typeid(ret).name() = f
ret = 10.5
$

str2やretのtypeidはちょっと独特だけど。

Sample/cpp/decltype/decltype/src/decltype at master · bg1bgst333/Sample · GitHub

後置戻り値型

C++11から、関数の定義において、戻り値型を引数リストの後に置くことができるようになった。

戻り値の型を後置する関数宣言構文 - cpprefjp C++日本語リファレンス

簡単な例を示す。

このように、本来戻り値型がある場所にはautoを置き、引数リストのあと、"->"、そして戻り値型を書く。

$ vi trailing_return_type.c 
$ g++ trailing_return_type.c -o trailing_return_type -std=c++11
$ ./trailing_return_type 
val = 10
$

結果は変わらないが、後述するdecl_typeを使う場合には、少し便利。

Sample/cpp/trailing_return_type/trailing_return_type/src/trailing_return_type at master · bg1bgst333/Sample · GitHub

forward

ユニヴァーサル参照の引数を持つ関数内で、その引数を別の関数に渡すときにmoveしてしまうと、ユニヴァーサル参照が左辺値だった場合に困る場合がある。

右辺値参照・ムーブセマンティクス - cpprefjp C++日本語リファレンス

このような場合に、

forward - cpprefjp C++日本語リファレンス

forwardが役に立つ。

custom_string.hに、

と書いて、

custom_string.cppに、

と書く。

main.cppは、

と書く。

func, func2, func3はユニヴァーサル参照、funcの中ではそのまま、func2の中ではsfd::move経由、func3の中ではstd::forward経由で渡してる。
外側でそれぞれの関数にそのまま渡す場合と、std::moveで渡す場合を試す。

$ vi main.cpp 
$ ./main 
str1 = ABCDE
str2 = VWXYZ
str1 ptr = 0x0083cc20
obj ptr = 0x0083cc20
ABCDE
inner_str ptr = 0x0083d0b0
str2 ptr = 0x0083cc40
obj ptr = 0x0083cc40
VWXYZ
inner_str ptr = 0x0083d0b0

obj ptr = 0x0083cc20
ABCDE
inner_str ptr = 0x0083cc20
obj ptr = 0x0083cc40
VWXYZ
inner_str ptr = 0x0083cc40
str1 ptr = 0x00000000
str2 ptr = 0x00000000

str3 ptr = 0x0083cc60
obj ptr = 0x0083cc60
ABCDE
inner_str ptr = 0x0083cc40
str4 ptr = 0x0083cc80
obj ptr = 0x0083cc80
VWXYZ
inner_str ptr = 0x0083cc80
str3 ptr = 0x0083cc60
str4 ptr = 0x00000000
$

str3は左辺値なのでちゃんと残っているし、str4は右辺値なので破棄されている。

Sample/cpp/forward/forward/src/forward at master · bg1bgst333/Sample · GitHub