Rossamu++

オールラウンダーになりたいと思っている僕っ娘の何の変哲もないブログ。

つまづいたっていいじゃないか、C++だもの

これはC++ Advent Calendar 2015 - Adventarの19日目の記事です。

どうも、ろっさむです。
本日二つ目の記事ですね、流石に少しだけ疲れましたが
僕はまだまだ元気です。0x15歳だしネ。

さて、今回のテーマは

C++初心者でも使える3つのテクニック」

となりました。
対象は中級者という枠組みに片足の先っぽを突っ込んでる方です。そう、僕みたいな。
メタプログラミングについて書く予定でしたが
プログラミング言語C++第4版」を読んで勉強しているうちに
色々書きたくなったので変更です。すいません。

紹介するテクニックは以下の通りです。

  1. インタフェースと実装の名前空間は分離しよう。そして平均的ユーザ用インタフェースと熟練者用インタフェースも区別しよう。
  2. 返すべき結果が大規模であればムーブコンストラクタを利用しよう。
  3. 大規模テンプレートとある程度以上文脈に依存するテンプレートは分割してコンパイルしよう。

それではいってみヨーカドー。


1.名前空間を用いたテクニック手法

これから極端な例を示します。

例えば今、貴方が何らかのシステム開発に携わっていたとします。
既存のソースコードを使用しつつ追加機能を開発しなければいけない場合に、
「あの機能を使いたいんだけど、どの関数を呼び出せばいいんだ?」と困ってしまいました。
使いたい関数が恐らく含まれている名前空間を見つけましたが、
複数の関数が以下のように記述されています。

namespace Parser{
    double prim(bool);
    double term(bool);
    double expr(bool);
}

それぞれの関数の中身を見てみると、
必要となるのユーザ用の機能はどうやらexpr()らしいぞい…。

これはいけません。
ユーザに示すインタフェースはもっと単純である必要があります。
Parser名前空間を次の二つを提供するように改良しましょう。

  • Parserを実装する関数用の共通環境
  • Parserのユーザに提供する外部インタフェース
//parser.h
//ユーザインタフェース
namespace Parser{
    double expr(bool get);
}

//実装者用インタフェース
namespace Parser{
    double prim(bool get);
    double term(bool get);
}

これで少しは改良されました。
ユーザ用インタフェースと実装者用インタフェースとで
名前を変えることも可能です。

//parser.h
//ユーザインタフェース
namespace Parser{
    double expr(bool get);
}

//実装者用インタフェース
namespace Parser_impl{
    using namespace Parser;

    double prim(bool get);
    double term(bool get);
}

_implを付けることで実装者用インタフェースを
わかりやすくしました。
これは大規模プログラムの場合によく用いられます。

しかしプログラムの物理的な構成が
そのままファイルで分割した名前を提供するので
必ずしもこうする必要はありません。

//parser.h
//ユーザインタフェース
namespace Parser{
    double expr(bool get);
}
//parser_impl.h
#include "parser.h"

//実装者用インタフェース
namespace Parser{
    double prim(bool get);
    double term(bool get);
    double expr(bool get);
}
#include "parser_impl.h"

double Parser::prim(bool get) {/*...*/}
double Parser::term(bool get) {/*...*/}
double Parser::expr(bool get) {/*...*/}

これで完了です。
この構造は大規模なモジュールでなければ不適切です。
現実的規模のモジュールでは個々の関数が必要とするファイルを
#includeするのが一般的です。

この構成を利用する最大の理由は、
プログラミングの際に考慮するべき部分を局所化できることです。
複数ヘッダ構成だと「◯◯のコードが何に依存しているか」を
正確に把握しやすくなり、それ以外のプログラム部分を無視できます。
局所化がうまくいくと、モジュールのコンパイルに必要な情報量が削減でき
短時間でコンパイルできるようになります。(1/1000になる可能性も)

また、実装者用インタフェースとユーザ用インタフェースを区別することによって
一般ユーザと熟練者用ユーザのそれぞれに丁度良い機能を提供することができます。
例えば一般ユーザには簡素化されたインタフェースを、
熟練者用ユーザには拡張されたインタフェースを提供できます。
DirectX(熟練者用)とDXライブラリ(一般用)みたいな感じですね。

単一ヘッダ方式と複数ヘッダ方式のどちらにするかの選択は
プログラムを構成するパーツの局所局所で変わってきます。
また、単一ヘッダ方式と複数ヘッダ方式は二社択一の性質ではなく、
システムの進化とともに見直すことになる相互補完的性質のテクニックです。


2.大きい返却値はムーブで

引数には二つの選択肢があります。
皆さんご存知の通り、「値渡し」と「参照渡し」ですね。
4ワード以下の小規模なオブジェクトなら値渡しが最高の性能を得られます。
しかし、引数の受渡しと利用の性能は
マシンアーキテクチャコンパイラのインタフェース規約、
引数がアクセスされる回数(参照渡し引数よりも値渡し引数への
アクセスのほうが高速である場合が殆どである)に依存します。

例えばMatrixの場合は大規模オブジェクトの場合は参照渡しの方が良いです。

//const参照渡し
Matrix operator+(const Matrix&, const Matrix&);

多くの場合、演算子は何らかの結果を返却します。
新しく作ったオブジェクトを指すポインタや参照を返却しようとするのは
あまりよろしくありません。
表記上の問題にやメモリ管理問題に繋がります。
つまり、オブジェクトは値として返すべきです。
ここでムーブ演算を定義して使いましょう。

ムーブとはなんぞや?

という人には更に詳しく書いてあるこちらの方々のブログを
オススメさせて頂きます。

C++のmove semantics完全に理解した - すてにゃんのガチ勢日記
本当は怖くないムーブセマンティクス - yohhoyの日記(別館)

一読すればムーブについては大体わかると思います。
すいません、短くて。


3.テンプレートを分割してコンパイル

テンプレートを利用するコードの構成方法として
合理的でわかりやすい方法が以下のように三つあります。

  1. 翻訳単位内でテンプレートを利用する前に、その定義をincludeする。
  2. 翻訳単位内でテンプレートを利用する前に、その宣言のみをincludeし、テンプレート定義はその翻訳単位内でその後includeする(利用箇所の後でもOK)
  3. 翻訳単位内でテンプレートを利用する前に、その宣言(のみ)をincludeし、他の翻訳単位でテンプレートを定義する。

ただ、技術的及び歴史的な理由から、テンプレート定義と
利用箇所を分割コンパイルする3は提供されていません。
これまで広く用いられている方法はテンプレートを利用する
全ての翻訳単位でそのテンプレートの定義をincludeして、
重複するコードの削除について、処理系によるコンパイル時の
最適化に委ねるというものです。

たとえばout.hでテンプレートout()を定義したとします。

#include<iostream>

template<typename T>
void out(const T& t)
{
    std::cerr << t;
}

そして、out()を必要とする箇所でこのヘッダをincludeします。

//ファイルout.h
#include "out.h"
// out()を利用

つまり、out()の定義とout()が依存する全ての宣言を
それぞれのコンパイル単位でincludeします。
必要に応じてコードを生成し、冗長な定義の読み取り処理を
最適化するのはコンパイラに任せます。
この方法はテンプレート関数をインライン関数と同様に処理するものです。

この方式の問題点は、out()の定義だけを目的として
includeしたはずなのに、includeされる別の宣言に誤って依存してしまうことです。
この危険性は先程の2の方法、名前空間を用いる方法、
マクロを避ける方法等で解消されます。
一般的なのはincludeする情報量を削減する方法です。
テンプレート定義の環境依存症を最小限に抑えるのが理想的と言われています。

2の方法では宣言と実装を二つに分けてユーザに両方をincludeさせます。

#include "out.h"
//out()を利用
#include "out.cpp"

これならテンプレートの実装がユーザコードに
望ましくない効果を与えてしまう機会が最小限に抑えられます。
しかし残念なことに、ユーザコードのマクロ等が
テンプレート定義に望ましくない効果を与えてしまう機会が増えてしまいます。
大規模プログラムではマクロの利用によるエラーは
見つけ出すのが非常に困難です。
テンプレートの文脈依存症は最小限に抑えるように気をつけつつ、
マクロに対しては疑ってかかるべきです。

具現化の文脈をもっと細かく制御する場合は
明示的具現化や、extern templateを利用しましょう。

以上、3つのテクニックでした。
もう一つ書こうと思ったんですが、
準備不足と資料不足で難しくなり書けませんでした。
他にも色々なテクニックがありますが、
それらは自分のブログを構築した際に
つらつら並べていこうと思います。

というわけでここまで読んでいただき有難うございました。
次はI (@wx257osn2) | Twitterさんです。

C++をのぞく時、C++もまたこちらをのぞいているのだ

この記事は初心者 C++er Advent Calendar 2015 - Adventarの19日目の記事です。
前回はそれC++なら#defineじゃなくてもできるよ | とさいぬの隠し部屋でした。

どうも、ろっさむと申します。
C++歴は2年いかない位で現在はゲームプログラマーになるために
色々お勉強している最中で御座います。

今回初めてAdvent Calenderに参加ということで
どう書くのか手探りでやっている状態となっています。
稚拙な文章になってしまいますが、どうぞよろしくお願いします。

さて、この記事のテーマは
純粋なC++について知ろう

となっております。
明らかに初心者向けです。すいません。
中級者上級者の皆様には物足りないかもしれません。
読み物としてサラーッと眺めて頂ければ有難いです。


1.C++とは?

 C++プログラミング言語の一種です(わかりきってますよね)。
大体なんでも出来ます。優秀な可愛い子です。
しかしなんでも出来るが故に、かなり多機能で複雑です。
でも、手がかかる子ほど可愛いと言いますし、
この記事の読者さんもそのくちでしょう。僕もそうです。

プログラミング言語は二つのお仕事を行います。

一つが、マシンに実行させる処理を
プログラマが指定するための手段を提供する事。

//「ようじょ」と出力するためにC++という手段を用いてマシンに「出力せよ」と指定しています。
std::cout << "ようじょ" << std::endl;

つまり、言語は出来るだけ「マシンに近い」ことが要求されます。

二つ目が、プログラマが処理内容を考える際に利用する
一連の概念を提供することです。
ここでは言語はできるだけ「解決すべき問題に近い」ことが要求されます。

それらを踏まえて、C++は以下に示す、
両方を提供するという考えに基づいて設計されています。

・メモリの効率的な利用と、効率的で低レベルな処理を提供できるようにするために
 組み込みの演算と型をハードウェアに直接マッピングすること。
・組み込み型と同じ記法、使い方、性能を持ったユーザー定義型を提供するために
 使いやすくて柔軟な抽象化のメカニズムを持つこと。

これらは二つはC言語とSimula言語を原点として考えられています。
(templateと例外処理は別方面からの刺激を受けてC++に追加したものらしいです(Clu等))

現在C++は、ほぼ全ての分野(PCや電話機、自動車、Amazon(ウェブ通販)、
Google(ウェブ検索)、コンシューマ系ゲーム制作等)で利用されています。

さすがC++!おれたちにできない事を平然とやってのけるッ そこにシビれる!あこがれるゥ!


2.C++の機能

続きましてはC++の様々な機能を紹介したいと思います。
と言いましても、流石に全てはご紹介できません。
さらっとだけ紹介します。あくまでも初心者向けに書いてます。

※全てを知りたい方は是非「プログラミング言語C++」を購入してみて下さい。
 全てが詰まっています。

まず、現在のC++のバージョンは14であり、既に次のC++1zが色々決まってきているようです。
ただ、Visual Studioは未だ14全ての機能には対応していないようです(大体使用可能なのは半分くらい)。
手っ取り早くコアな機能も試したいのであればWandbox等使うと良いかと思います。

ここでC++の機能をざーっと見てみましょう。

基本機能として…

  • 型と宣言

  L 基本型、論理型、文字型、整数型、浮動小数点数型、接頭語と接尾後、
  void、アラインメント、型の導出...etc

  • ポインタと配列と参照

  L void*ポインタ、nullptr、配列、文字列リテラル、多次元配列、constポインタ、
  左辺値参照、右辺値参照...etc

  • 構造体と共用体と列挙体

  L struct、POD、共用体、無名共用体、enum class、名前無しenum...etc

  L switch、if、範囲for、while、do、goto...etc

  L演算子、定数式、暗黙の型変換、ラムダ式、明示的型変換...etc

  • 関数

  L inline関数、constexpr関数、noreturn関数、参照引数、可変個引数、
   多重定義、マクロ、関数ポインタ...etc

  • 例外処理

  L エラー処理、finally...etc

  L using宣言、using指令、実引数依存探索、入れ子の名前空間...etc

  • クラス

  L コンストラクタ、デストラクタ、アクセス制御、explicitコンストラクタ、staticメンバ...etc

  • 標準ライブラリ

  L initializer_list、アサーションSTLコンテナ、STLアルゴリズム
   STL反復子、ユーティリティ、正規表現...etc

応用として
テンプレート、ジェネリックプログラミング、メタプログラミング、並行処理、タスク...etc

たくさん書きましたが、これらに関連するものや、これ以外にも細かく見ていくと、
キリがないくらいの機能がC++には盛り込まれています。
一つ一つ知っていくのも良いですが、基本的にはコードを書いている最中に
「こうゆう処理ないかな」「無駄を省くために何かできないかな」という場面で
調べて使っていくのが良いかと思われます。

もちろんちゃんと一つ一つ丁寧に学習していけば、
C++以外の言語を触った時に
「この言語ではC++のあの機能と似ている機能ないかな」と
自然と考えることができるようになり、作業が効率化されます。

どう学習していくかは人それぞれだと思いますよ。


3.C++の外部ライブラリ等

現在の代表的な外部ライブラリは「boost」であると思います。
「boost」とは次期C++標準とも言われる程の強力なライブラリの集合です。
具体的にどのようなものが含まれているかというと、

・現在の標準ライブラリに+αな機能を付けて便利にしたり、柔軟な機能を持たせる機能
・標準ライブラリにはない数学や物理等の専門的な式をサクッと使える機能

という感じです。
なので最初のうちはboostは必要ないと思います。
今の標準ライブラリに満足できなくなった時に手を出すべき代物ですね。

外部ライブラリとしては他にも

・POCO(Web開発)
・Qt(クロスプラットフォームアプリ開発)
wxWidgets(クロスプラットフォームGUIライブラリ)
Webkit(ウェブブラウザ用のレイアウトエンジンライブラリ)
・CGAL(計算幾何学)
・QuickFix(金融情報交換)
OpenCV(リアルタイム画像処理)
・Root(高エネルギー物理学)

等があります。

また、C++を用いて手軽にゲームを作りたい!DirectX難しい!
と思っている方には

・UE4(3D特化ゲームエンジン)
・OpneGL(2Dも3Dも)
・Cocos2D-X(2D特化ゲームエンジン)
・Siv3D(2Dも3Dも)
・DxLib(2Dも3Dも)

オヌヌメします。色々調べてみてください。
ちなみに最近のトレンドはUE4です。
UE4ではUnreal C++というC++を更に改良した(らしい)言語が
使えるみたいです。
ただし、某UE4のやばい人曰く、
大体はブループリントでええやん という感じです。

さて、ここまで駆け足でしたがいかがだったでしょうか。
初心者の皆さんはこんなチンケなブログではまだC++のCの字も味わってないと思います。
ですがC++の魅力を少しでもお伝え出来たら光栄であります。
ここまで読んでくださって有難うございました。

次は
shunonymous (@shunonymous) | Twitterさんです。

「オブジェクト指向でなぜつくるのか」について

今回は内定先からお借りした参考書

オブジェクト指向でなぜつくるのか」という

本を読ませて頂きました。

 

この本なのですが、

C++を学んでいる身としては

少し易しく感じる部分が多かったです。

 

ではどの部分が参考になったのか。

 

まず第一に、人に説明する時に

どうゆう順序で話せばいいのか、

どう表現したらいいのか、が勉強になりました。

 

この本自体オブジェクト指向入門者向けなので

とても丁寧にみっちりと

オブジェクト指向とは何か、

オブジェクト指向を使った時の利点、

様々な参考書で語られるオブジェクト指向のイメージと

本書でのオブジェクト指向のイメージの違い等

綴られていました。

 

オブジェクト指向技術を
一言で表現すれば
「難しいソフトウェア開発を
楽にする技術」である。」

 

オブジェクト指向
ソフトウェア開発全体をカバーする
総合的な技術になっている。」

 

この部分は

僕自身も「あぁ、なるほどなぁ」と思いました。

 オブジェクト指向とは一体何かを

とても簡潔に表していると感じました。

 

また初心者の方に

オブジェクト指向を説明する際に

気をつけなければいけない3つの点も

タメになりました。

以下に綴ります。

 

混乱要因1「用語の洪水」

特殊用語が大量にあるせいで
説明を聞いただけで
辟易する人が多い。

なので人に説明する際には
なるべく用語を使わずに説明する。

 

混乱要因2「比喩の乱用」

一般的に悪いものではないが
使いすぎると聞く側がそれぞれ
解釈をしてしまうため、
誤解を生む危険が大きい。

 

混乱要因「なんでもオブジェクト症候群」

オブジェクト指向
「物中心」あるいは「もの指向」
と言う意味だが、
言葉通りにするとなんでも
オブジェクト指向となる。
極端な抽象化のせいで
混乱させてしまいやすい。

 

僕も人にオブジェクト指向について

説明しなければいけない場面もあったのですが

その際に比喩表現を使いまくってたため

逆に「う~ん」と唸られてしまうこともありました。

 

ではどうしたらいいのか。

オブジェクト指向技術の
正しい理解のためには
三つの方針をとる。

1.紹介する用語や概念は最小限に。
2.比喩による説明は最小限に抑える。
  使う場合はその旨を説明する。
3.プログラミングの仕組みと、「もの
   中心」で物事をとらえる汎用的な
   考え方は別物とし、わけて説明。

 

以上の事柄に

今後は気をつけていきたいですね。

 

そして第二に、

オブジェクト指向を高めるコツや

開発プロセスについて等について勉強することができました。

 

それから、エージェント指向、

アスペクト指向についても少し解説が入っており

オブジェクト指向以外にもあるのだと

初めて知ることが出来ました。

 

文字が大きく丁寧でわかりやすい説明ながらも

色々と凝縮されて書かれているので是非手にとって

読んで頂きたい一冊だと思いました。

 

次は「アジャイルサムライ」を読んでみたいと思います。

 

 

 

オブジェクト指向でなぜつくるのか 第2版

オブジェクト指向でなぜつくるのか 第2版

 

 

C プログラミング入門以前について

12月後半のSapporo.cppの勉強会にて

らぴすさんという方から

「C プログラミング入門以前」

という本をお借りしました。

 

Cプログラミング入門以前

Cプログラミング入門以前

 

 

今後C++をやるにおいて

メモリの中身等についてきちんと

知っておく方が良さげとのこと。

 

というわけでこの本を借りての感想を

つらつら述べていきます。

 

この本なのですが、

C言語入門者向けというよりは、

予めCの予備知識を持っている方向けだと

僕は感じました。

 

基本的に知っている部分は流し読みしつつ

目新しいところはメモや写真を取りつつ…

で進めていったのですが、

目新しいことが多い多い。

ソムノートを使いながらの勉強でしたが、

あっという間に90項目メモしていました。

 

C++を勉強してはいましたが

それはあくまでも文法部分や

機能に関しての話しであって

ハードの中身に関してはカラッポだと

痛感させられましたね…。

 

特に専門用語に関してです。

 

まず最初に「そうだったのか」と驚いたのが

stdio.hの口頭での読み方

ですね…。

 

これ

「スタジオヘッダー」

と呼んでました。

正しくは

スタンダード・アイ・オー・ヘッダー

ですね、はい。

Twitterで流してみると僕のように

スタジオヘッダーと呼んでいた方が

多かったらしく、中々の反響を貰いました。

 

それから新しく蓄えた知識として

「バス」

についてです。

 

・データバス

・アドレスバス

・コントロールバス

 

に関しては初耳でした。

この辺はメモリの図を用いて

丁寧に説明されていたので

とてもわかりやすかったです。

 

その他にもエクスターナル変数、

バイトオーダー、リダイレクト、などなど…。

 

普段見ない言葉が多く、

読んでいてとても楽しかったです。

 

次は3月14日の旭川勉強会に向けて

アルゴリズムの本を勉強頑張るぞい!

 

Nature of Code -Processingではじめる自然現象のシミュレーション-

Nature of Code -Processingではじめる自然現象のシミュレーション-

  • 作者: ダニエル・シフマン,Daniel Shiffman,尼岡利崇,鈴木由美,株式会社Bスプラウト
  • 出版社/メーカー: ボーンデジタル
  • 発売日: 2014/09/16
  • メディア: 大型本
  • この商品を含むブログを見る
 

 

始めてみたけど特に書くことがないので本の感想とかまとめでも綴ろうかなって

ブログって何書けばいいかわからないので

参考書とか読んだまとめやら感想やら、

勉強会のこととか適当に

不定期に書いていこうかなって、

そんな感じです。