C++ 学習記(1): まずは環境確認整備
業務の都合でいままで書いたことのないC++を使わざるを得なくなった。
業務のほうは既存のC++コードを書き換える方向なので、まあなんとかなるだろうと思っているんだけど、スクラッチから起こすことができないので
makeの書き方も-Iや-Lオプションの意味もautomakeも何もわかっていない。
ということでやばいだろうということでよちよち勉強していくことにする。
やらないといけないであろうこと
MakeFileの読み方書き方、automake, cmake
コンパイルオプション
ldconfig, LD_LIBRARY_PATHの意味と設定方法を理解する
OpenMP / MPIによる並列化
参考文献
完全にC++は未知だけどもJavaなら結構経験積んでいたので、私の知り合いの中で最もプログラミングに長けた大先輩におすすめしていただいた
を買いました。とりあえず、わからないことがあったらこれにあたってみると、1つくらいは例が載っているのでだいたい乗り切れています。*1
設定
プログラム経験: Java(メイン、10年以上), Python(ここ2年ほどメインで使ってる)
OS: ubuntu14.04 on VMware
エディタ: emacs
IDE: JetBrains IntteliJ IDEAとPycharmがないとJavaもPythonもかけない
IDE絶対ほしいけど、JetBrainsのC++って有償なんだよね、確か・・・
現在の状況
何が入っているか確認するのもあってapt-get installでそれっぽいライブラリを指定してみる。
ちょっと探すと
という記事が見つかったので、載っているやつはインストールしておく。
Hello, world
まずはhello world.
(hello.cpp.cpp)
#include <iostream>
#include <cstdlib>int main(){
std::cout << "hello world" << std::endl;
return 0;
}
コンパイルして実行。
% g++ hello_cpp.cpp
% ./a.out
*1:const参照とか&, *の使い方とか私にとっては完全に悪夢なので、毎回見ています
Linux便利コマンドの覚書
コマンドラインでいろいろ文字列処理できるよっていうね。
常にpythonやperlさん使うより、覚えていたらずっと早かったりする。
そこで、便利だったコマンドを、実際の自分のusageに即してメモする。
というか100本ノックの第二章やってるだけです
cut
デフォルトでは、タブ区切りファイルからコラムを切り出せる。
tsvファイルがあったときに、その第1, 3コラムだけを抽出するには
cat hoge.tsv -f1,3
結果がほしいときは
cat hoge.tsv -f 1, 3 > output.tsv
とする。
区切り文字を変える時には-dをつける
など
sed
文字列変換。
で、hoge.txt内の"ABC"がすべて"DEF"に置換されてreplaced.txtに出てくる
paste
二つのファイルを、同じファイル行数ごとに連結する。
これ、実はすごく強力ではないか?入力ストリームを2つ同時に進めるってのは普通のプログラムだと難しいような気が(少なくとも perlの <>だけではできない?)
paste file1.txt file2.txt > file12.txt #concat with tab (default)
paste -d":" file1.txt fil2.txt > file12-colon.txt # concat with colon. -d to specify the connecting character
paste -d"ABC" fileq.txt file2.txt > file12-A,txt # どうも文字列の最初の1文字しか使わないようだ。この場合は"A"で連結される
sort
入力されたファイルを、ソートして並べ替える。
これまた神コマンドかもしれない。
例えば
高知県 江川崎 41 2013-08-12
埼玉県 熊谷 40.9 2007-08-16
岐阜県 多治見 40.9 2007-08-16
山形県 山形 40.8 1933-07-25
山梨県 甲府 40.7 2013-08-10
みたいな(タブ区切り)データがあったとき
sort -n -k3 data.txt # 第3列 (-k3)を、数値として(-n)、昇順にソート
大阪府 豊中 39.9 1994-08-08
岐阜県 美濃 40 2007-08-16
群馬県 前橋 40 2001-07-24
山形県 酒田 40.1 1978-08-03sort -n -k3 -r data.txt # -rで降順になる
山形県 酒田 40.1 1978-08-03
群馬県 前橋 40 2001-07-24
岐阜県 美濃 40 2007-08-16
大阪府 豊中 39.9 1994-08-08
これは圧倒的便利
cat
cat自体はまあ普通だけど、頭のよい使い方を
cat コマンド | コマンドの使い方(Linux) | hydroculのメモ
で見かけたので下記に引用する。
行数が膨大なテキストファイルに対してなにかの処理をしたい。
処理に時間がかかってしまうが、その “なにか” を処理させるワンライナーが正しいかどうか不安で何度か試行錯誤する必要がある場合に、試行錯誤中は、テキストファイル全体を処理するのではなく、
head
でファイルの一部だけを処理してみる。ワンライナーが完成したときに、コマンド履歴の
head
をcat
に書き換えるだけで処理を完成させることができる。“なにか” が仮に文字コード変換だとすると、こんな感じ。
## テキストファイルの文字コードがわからないが、とにかくUTF-8にしたい $ head huge.txt | nkf --guess CP932 (CRLF) ## CP932 というのをUTF-8にするにはどうしたらいいんだっけ? $ head huge.txt | nkf -sW ... ## 違った、文字化けしちまった、こっちかな? $ head huge.txt | nkf -Sw ... ## 合ってた。さて、改行コードはどうなってる? $ head huge.txt | nkf -Sw | nkf --guess UTF-8 (CRLF) ## 改行コードも直したい $ head huge.txt | nkf -Sw -Lu | nkf --guess UTF-8 (LF) ## OK。じゃあ、本番 $ cat huge.txt | nkf -Sw -Lu > result.txt
最後の本番のコマンドは
nkf -Sw -Lu huge.txt > result.txt
でもよいのだが、直前のコマンド履歴のhead
をcat
に書き換えるだけのほうが、タイピングが楽で間違えないのである。このときcat
はほとんど意味のある仕事をしないが、タイピングを楽にすることに意味がある。
screenの使い方!
実に10年ぶりくらいぶりにマシンをつけっぱなしにできない状況になったので、改めてscreenを再勉強。
screenの特徴は、一つのターミナル画面上で番号の切り替えで多数のセッションを作ることだけど、もう一つの特徴として「セッションはバックグラウンドで走っているのでそのターミナルを殺しても生き残る」というのがある。
ので、手元のマシンからsshで計算サーバにログイン、計算を回すという状態のときに
i) 計算サーバでscreenして新しい仮想ターミナルを作成、ログイン
ii ) 計算ジョブを投げる
iii) screenしたターミナルから抜ける
と、あとはsshが切れても計算サーバ上では ii) のジョブが生き残ってくれる。
で、後日改めて計算サーバ上でscreenしていたターミナルにログインすれば計算結果が回収できるというわけ。
portforwarding + autossh + sshfsと合わせて利用するので、ここで必要なコマンドを備忘録的にメモ。
新しいスクリーンを始める:
screen
スクリーンから離れる: detach from screen(殺さないで親ターミナルにもどる)
Ctrl-a d
入れ子でスクリーンするとわかりにくいので、新しくスクリーン作るときはいちいちスクリーンから離れて、親ターミナルに戻ったほうが良さげ。
今あるスクリーンを調べる: list screens
screen -ls
スクリーンのIDが並びます
指定のスクリーンに戻る: resume screen
screen -r ID
スクリーンを殺す
exit
ただのターミナルなのでね
ansible導入テスト(Docker, Jenkinsへの道 on Windows(3))
続いて、構成管理ツール(?)であるansibleを試す。
ansibleのほうがchefよりも後発でネガをつぶしているのと簡単構成向きらしい。
試す
これにならって、サーバ二つ構成の最小セットアップをvagrant + virtual box上に構成、そこで片方のサーバでもう片方をansibleで管理するテストを行う。
作った環境ではcentos6.5なので、Vagrantfileはちょっとだけ変わる。
Vagrant.configure(2) do |config|
config.vm.define "controller" do |node|
config.vm.box = "centos65"
config.vm.hostname = "controller"
config.vm.network "forwarded_port", id: "ssh", guest: 22, host: 2210
config.vm.network "private_network", ip: "192.168.100.10"
end
config.vm.define "target" do |node|
config.vm.box = "centos65"
config.vm.hostname = "target"
config.vm.network "forwarded_port", id: "ssh", guest: 22, host: 2220
config.vm.network "private_network", ip: "192.168.100.20"
end
end
vagrant upで長らく待つとちゃんとcontrollerもtargetも起動する。
こけた
ちょっと何かupdateしてしまったら、ビルドが壊れた・・・
kernel-develのversion有ってないよってなる。
そのときは
を参照して下さい。
無事起動したらansibleインストール
よしよし。ということでcontrollerサーバにsshして、ansibleをyum installする。
あれ、なんかtargetになってるが、まあいいや。
targetからcontrollerを支配しよう・・・・
つながったポイ??
「オブジェクト指向と10年戦ってわかったこと」が素晴らしかった
これです。
自分はJava使い*1なのですが、オブジェクト指向の価値を全然活かせていないなぁと常々思っていました。
色々原因がありそうですが、この記事にあるようにしっかり考えてないからだ、ということがわかりました。
幾つか、自分に刺さったところを自分のために引用しておきます。
気になった人はリンク先の本文をぜひ読んでください。
クラスはとっかえひっかえするものをクラスにする
オブジェクト指向で書く理由、それは変更に対して柔軟に対応するためです。
(省略)
オブジェクト指向によるアプリケーション開発は、変更されない箇所を軸に、頻繁に変更される箇所をクラスに抽出するプログラミングスタイルです。
継承は様々な具体的なクラスを抽象化するためのボトムアッププロセスで、トップダウンにすべきではない
継承は機能を受け継ぐためのものではありません。継承の本質は、犬や猫を「動物」という抽象概念としてまとめ上げられるインターフェイスなのです。
その証拠として、別のクラスの機能を利用する方法にコンポジションがあります。コンポジションを使えば人間がパーツを組み合わせて「車」を作るような自然なオブジェクトの作り方ができるし、実は継承よりコンポジションの方がよく使います。
ポリモーフィズムは抽象のスーパークラスを扱う(ことによって見通しを良くする)
継承の本質はインターフェイスであると説明しましたが、ポリモーフィズムはそのインターフェイス(抽象)に対してプログラムするということです。
インスタンスをnewするのはメインクラス。メインクラスは素材を出して処理する調理場。
そのため、ファクトリを作るまでもないインスタンス生成はメインクラスで行うようにしましょう。メインクラスでnewしたインスタンスを他のクラスに渡すのです!
(省略)
メインクラスは調理場のような存在であり、メインクラスに疎結合性やモジュール性は必要ありません。そのため、メインクラスがnewの接着剤でベトベトに汚れてしまっても何も困ることはないのです。
カプセル化は難しい
しかし、小刻みにブレーキを踏まなければスリップし、小まめにギアチェンジする必要があり、カーブするときは倒れないように体重移動をしなければ倒れてしまう自動車があったら、僕はそれを運転できません。複雑だからです。だけど、ブレーキにはABSを搭載し、ギアはオートマチックで、カーブするときは倒れないよう重心が設計されていれば、あれこれ考えず運転できます。
つまりカプセル化とは複雑な部分を隠し、無駄な操作をしなくても良い状態にそのものを洗練させ、分かりやすい状態にするということです。
(省略)
実はこの「無駄を省き洗練させてわかりやすくする」というのはオブジェクト指向の原則というより、より抽象度の高い「デザイン」の原則なのです。
オブジェクト指向に不可欠なのはカプセル化ですから、つまり、オブジェクト指向でプログラミングする人にはデザインのセンスが必要になるということになります。
そんなもの、難しくて当然です!
カプセルにはただしい名前が必要
自動車には「自動車」という名前が、エレベーターには「エレベーター」という名前が付けられています。もしあなたが何かをカプセル化した場合、そのものにまだ名前が付いていない時は、それに正しい名前をつけるということが、カプセル化の最後の仕上げになります