おにくが足りない

頬が痩けてきた。明らかに体に肉が足りていない。

ということでGoogle Mapsでせっせとお肉を検索して、自宅近くのステーキ屋さんに行ってきた。 非常によくて、そこそこの値段ががっつりお肉が食べられるのでこれは通うことになりそう。

おにくセットの写真
25ドルくらいのおにくセット


シンガポールはなにもかもの値段が高くて、無意識のうちに食べ物を買って食べることを躊躇してしまうので非常によくない。 道行く人々が痩せているかめちゃくちゃ太っているかの2通りなのは健康的な食べ物が高いからだと睨んでいる。 仕方ないので自炊するためのフライパンやら調味料やらを購入してきた。 レンジフードが日本と違って室内につながっているためあんまり自炊したくなかったのだけれど、健康のためにはやるしかないのだ。 調味料は徐々に揃えていきたいので、まずは塩と酒があればできる酒蒸しから。

dailyportalz.jp

massifヒーププロファイラ

massifはvalgrindに同梱の、プログラムがメモリヒープをどれくらい使っているかをプロファイリングしてくれるもの(情報が無)。

インストールをして:

sudo apt install valgrind massif-visualizer

実行:

valgrind --tool=massif --time-unit=B --stacks=yes your_program program_args

するとmassif.out.XXXX(Xは数字)というファイルができるので、これをmassif-visualizerに食わせる:

massif-visualizer massif.out.4543

すると以下のリンクのようにどの関数がどれくらいヒープを使っているかが可視化される。超べんり。 apps.kde.org

こんな便利なプログラムがフリーで使えるのは本当にありがたい。

www.valgrind.org

喉がずっと痛い

のどがいたい。

この2,3年ほど、一旦喉が痛くなると1,2ヶ月、場合によってはそれ以上ずっと痛い、という症状が続いている。 痛くなるきっかけ自体は、乾燥でやられた、とか大きい声の出した、とかわかりやすいのだが、 うっかり痛くなるとその痛みが取れず、結果トータルで1年の半分くらい喉が痛い、という状態が続いている。

普通の市販薬や処方薬は効かず、抗生物質を1,2週間分処方してもらって、その後2ヶ月ほどかけてじわーっと治っていくような感じである。

今回は

  • 2/2あたりから痛くなりはじめ、
  • 2/9にガラガラ声のまま研究会で発表をし、
  • 2/16に学内の病院で炎症止めの内服薬を処方してもらうもほとんど効かず、
  • 3/2に再度受診すると、3日分の抗生物質の処方とともに、規則上covid19の疑いあり、という扱いになってそのままGrabで自宅に直行、3日間の自宅隔離命令が出た。 スーパーにも行けないため、ちゃんとした食べ物はないぞということでfoodpandaで適当にたべものを購入。べんり。
  • 翌日3/3にまたGrabで学校に行き、隔離されたままPCR検査、またGrabで自宅に帰って自宅隔離。
  • さらに翌日3/4の夜には検査結果が出て陰性との連絡があり安心。

で今日3/13現在まだ痛い。老化?ストレス?何が原因なんだろう。

色々試したりもしていて、これは漢方のハチミツのようなやつ: f:id:ompugao:20210218160332j:plain

ちょっと高いけど痛みを感じにくくなるので割と好き。 同じ会社から出ているのど飴も結構おいしい。龍角散のど飴よりも好みかもしれない。 f:id:ompugao:20210313150052j:plain

早く治ってほしい。

追記 5/31 咽喉頭酸逆流症らしい。 オメプラゾールをたくさん計2ヶ月分処方された。 イガイガが取れるといいな…

Asus ROG Zephyrus G14 GA401のセットアップ

購入した新しいPC(Asus ROG Zephyrus G14 GA401)が届いたのでセットアップした。 ompugao.hatenablog.com

購入後に新モデルのリリース時期が発表されて(4月末発売開始)少しぐんにょりしたものの、ラップトップは新しすぎるとlinuxを入れるのに苦労するので、まぁよかろうと思い直した。 あーでもRTX20XXよりRTX30XXのがいいよなー(ブツブツ ASUS Store(エイスース ストア) - 【14インチ】ゲーミングノートパソコン一覧

リリースから1年もすると、ubuntuがout of boxで動くんだからありがたい。 今回初めてbtrfsを利用してファイルシステムのスナップショットが取れるようにした。

以下手順:

  • ubuntu20.04のインストーラをダウンロードして、startup disk creatorでusbに入れる。
  • /をbtrfs、/bootをext4にしてインストールする。usb-ethernet変換器をつないでインストーラを起動しないとwifiのインターフェースを認識してくれなかった。
  • とりあえずetckeeperをいれる。
sudo apt install git etckeeper
sudo mkdir -p /mnt/btrfs_root
sudo mount UUID={{btrfsのfile system rootのuuid}} /mnt/btrfs_root/
cd /mnt/btrfs_root
sudo btrfs subvolume create @var
sudo btrfs subvolume create @var/lib/docker
sudo btrfs subvolume create @snapshots
echo "UUID={{btrfsのfile system rootのuuid}} /var/lib/docker           btrfs   defaults,subvol=@var/lib/docker 0       2" |sudo tee >> /etc/fstab
echo "UUID={{btrfsのfile system rootのuuid}} /var/lib/docker           btrfs   defaults,subvol=@var/lib/docker 0       2"|sudo tee >> /etc/fstab
echo "UUID={{btrfsのfile system rootのuuid}} /var/tmp           btrfs   defaults,subvol=@var/tmp 0       2"|sudo tee >> /etc/fstab
echo "UUID={{btrfsのfile system rootのuuid}} /var/log           btrfs   defaults,subvol=@var/log 0       2"|sudo tee >> /etc/fstab
echo "UUID={{btrfsのfile system rootのuuid}} /.snapshots           btrfs   defaults,subvol=@snapshots 0       2"|sudo tee >> /etc/fstab
sudo snapper create-config

kernel 5.11を入れると上記asus-linuxの諸々が要らなくなるけれど、 Kernel/MainlineBuilds - Ubuntu Wikiからインストールしたupstream kernelに Proprietary GPU Drivers : “Graphics Drivers” teamnvidia-driverを入れようとすると、5.9.?(わすれた), 5.10.22, 5.11.1, 5.11.5のどれを使ってもubuntuの起動が途中でハングするのでやめた。やはり公式こそが正義。

18万円くらいでこんなスペック(Ryzen9 4000, RTX2060 Max-Q, 16GB Memory, SSD 1TB, 1.7kg)のPCが買えるのはすごい。ありがたし。

ポケモンで学ぶC++オブジェクト指向入門

以前妻にc++のクラスの使い方を教えたときに、ブログ記事にしたらいいのに、と言われたので公開しておく。

対象者:intとかdoubleの変数やその配列を扱え、関数を作ったり使ったりできる。ポインタも一応わかる。でもclassの使い方がわからない。そんな人。

記事を読むと?: c++でif else分岐の多かったコードを少し見通しよくできるようになる。 (c++で継承を利用したポリモーフィズムなプログラムを書けるようになる)

本題:

あなたはポケモンを実装しているプログラマです。 ポケモンバトルにおける"こうげき処理"をc++で実装しようとしています。 「プレイヤーがてもちのポケモンから一匹えらんで、あいてのポケモンをこうげきする」という処理について考えています。 ここでは、ポケモンは一つのわざしか覚えていないと仮定します。 一旦c++の正しい文法は無視して、実直に書くとこうなります。

ポケモン = ポケモンを選ぶ();
if (ポケモン == ピカチュウ) {
    十万ボルト(ポケモン);
} else if (ポケモン == ゼニガメ) {
    ハイドロポンプ(ポケモン);
} else {
    ...
}

ポケモンの数だけif elseが続きますね。 ポケモンが増えるごとにこの処理を変更しないといけません。 大変です。

そこで、オブジェクト指向プログラミング(Object Oriented Programming)です。 以下のように考えます。こちらも一旦正しいc++の文法を無視します。

// 基底クラス
class ポケモン {
    void こうげき();
};

// ポケモンクラスを"継承"したピカチュウクラス
class ピカチュウ : ポケモン {
    void こうげき() override {
        十万ボルト();
    }
    void 十万ボルト() {
        // 十万ボルトの実装
    }
};

class ゼニガメ : ポケモン {
    void こうげき() override {
        ハイドロポンプ();
    }
    void ハイドロポンプ() {
        // ハイドロポンプの実装
    }
};

まず、「ポケモン」というクラスを作ります。 これはポケモンがどういうことができるか、という特性を示してくれます。 ここではポケモンは「void こうげき()」関数を持っていることがわかります。

そしてポケモンクラスの子供にあたる「ピカチュウ」クラスを作ります。 ピカチュウポケモンなので自然です*1。 これを基底クラスを継承して派生クラス(子クラス)を作る、といいます。 そしてピカチュウクラスの中で、ピカチュウは実際にどのようなこうげきをするのかを具体的に記述します。 ピカチュウは十万ボルトが使えるので十万ボルトについて書きましょう。 ゼニガメについても同様です。

ピカチュウクラスは、あくまでピカチュウという種族についての書いているだけです。 「サトシのピカチュウ」、というある個体を表現するにはこうです。

ピカチュウ  サトシのピカチュウ();

この「サトシのピカチュウ」のことをピカチュウクラスの「インスタンス」と呼びます。

int i(0);

のようにintの変数を宣言するのと同じことです。 intがピカチュウになっただけです。

ポケモンがこうげきするときはこのように書きます。

サトシのピカチュウ.こうげき();

サトシのピカチュウへのポインタを知っているときには"->"を使って書きます。

サトシのピカチュウ->こうげき();
// 以下と同じ
(*サトシのピカチュウ).こうげき();

さて、「てもちのポケモンから一匹えらんで、あいてのポケモンをこうげきする」という処理はどのように書けるでしょうか。

ポケモン* 手持ちのポケモン[2];
ピカチュウ  サトシのピカチュウ();
ゼニガメ サトシのゼニガメ();
手持ちのポケモン[0] = &サトシのピカチュウ;
手持ちのポケモン[1] = &サトシのゼニガメ;

int i = ポケモンを選ぶ();
手持ちのポケモン[i]->こうげき();

if elseを使わなくて済み、 ポケモンの種類が増えた場合、例えばミュウツーが生み出された場合には、 ポケモンクラスを継承したミュウツークラスを作るだけです。べんりですね!

さて、c++を使って正しい文法で実装してみましょう。

#include <iostream>
 
class Pokemon {
public:
    // コンストラクタ
    Pokemon(const std::string& nickname) {
        this->nickname_ = nickname;
        // nickname_ = nickname; と省略できる
    }
    // デストラクタ
    virtual ~Pokemon() {
    }
    virtual void attack() = 0;
protected:
    std::string nickname_;
};

class Pikachu : public Pokemon {
public:
    Pikachu(const std::string& nickname) : Pokemon(nickname) {
    }
    virtual ~Pikachu() {
    }
    void attack() override {
        std::cout << nickname_  << "の十万ボルト!" << std::endl;
    }
};

class Zenigame : public Pokemon {
public:
    Zenigame(const std::string& nickname) : Pokemon(nickname) {
    }
    virtual ~Zenigame() {
    }
    void attack() override {
        std::cout << nickname_ << "のハイドロポンプ!" << std::endl;
    }
};


int main() {
    int i;
    Pokemon* monsters[2];
    monsters[0] = new Pikachu("サトシのピカチュウ");
    monsters[1] = new Zenigame("サトシのゼニガメ");
    std::cin >> i;
    if (i >=0 && i < 2) {
        monsters[i]->attack();
    }
    delete monsters[0];
    delete monsters[1];
}

なんだか色々増えましたね。

まず「コンストラクタ」と「デストラクタ」はそれぞれそのインスタンスを作ったときと消えるときに呼ばれる関数です。 ポケモンの個体にはニックネームがあるので、そのポケモン個体を宣言し生み出す時に同時にニックネームも設定したいですね? まず、ポケモンクラスの中にニックネームを格納する部分を作ります。 それがstd::string nickname_;の部分で、これをクラスメンバ変数と言います。 Pickachu("サトシのピカチュウ");ピカチュウクラスに渡されたニックネームが巡り巡って、 this->nickname_ = nickname;の部分でnickname_に設定されます。 thisというのは今作ったり消したりしようとしているポケモン個体(インスタンス)へのポインタです。 各個体ごとに別のニックネームが設定されることになります。

    virtual void attack() = 0;

virtual なんとか = 0;は純粋仮想関数といいます。継承先(ピカチュウ等各ポケモンクラス)でちゃんと実装してくださいね〜でないと空っぽのままですからね〜と指示しています。

    new Pikachu("サトシのピカチュウ");
    delete pikachu;

new/deleteはご存知でしょうか?まぁPikachu satoshi_pikachu();と同じようなもの*2ですが、newはポケモン個体を作った後ポインタが帰ってきます。ポインタの先の実体はスコープを抜けても終了処理が行われずメモリリークするので、使わなくなったらdeleteをしなければなりません。普通はnew/deleteを使わずshared_ptrやunique_ptrを使います。気になったら調べてみてください。

また、publicやprotectedという言葉が出てきました。他にもprivateがあります。 これはアクセス指定子といってその変数やクラスが内外のスコープからアクセスできるかどうかを示しています。

  • publicは、どこからでもアクセスできます。
  • protectedだと継承先のクラスでは見えますが(main関数など)外からは見えません。
  • privateだと宣言したクラスでしかアクセスできません。

という意味になります。

class Zenigame : public Pokemon {

この部分のpublicについての解説は省略します。大抵の場合でpublicを用います。

実行してみましょう。

$ g++ pokemon.cpp -o pokemon
$ ./pokemon
0
サトシのピカチュウの十万ボルト!
$ ./pokemon
1
サトシのゼニガメのハイドロポンプ!

いいですね!

*1:これらはis-aの関係にあります。 ja.wikipedia.org

*2:いいえ、全然違います。普通のsatoshi_pikachuはスタック領域に存在しますが、newで作られたピカチュウはヒープ領域にいます。 メモリとスタックとヒープとプログラミング言語 | κeenのHappy Hacκing Blog

新しいパソコンをポチった

ラボから借りているPCのディスクが小さすぎて(ubuntuに130GBくらい)、 すぐにdisk fullになってしまい何をするにもやりづらいので新しいパソコンを購入した。

ラップトップと据え置きで迷ったものの、持ち歩ける方がロボ屋としてはよかろうと思いラップトップを物色した。 軽くて、そこそこよいnvidiaGPUが乗っているラップトップを探すものの、全然ない… これ↓が唯一の候補だった。

1.7kgでRTX2060がのってて、メモリも一応増設できて、ryzenで…ryzenかー、初めてだから怖いなー使うプログラムが全部ちゃんと動くといいなーと不安になりながらポチッとした。 熱い、電池が2時間しかもたない、などなど色々レビューが散見されるものの、小さい機体にグラボのってるんだからその辺は割り切った。 モニターが明滅する個体があるらしいが、そういうのはすぐに症状が出て返品できるかな、と判断した。

いい子が届きますように。

ソフトウェアをお金を払う

学生の頃はお金を使うことにすごく抵抗感があったが、 社会人となって給料を貰うようになってからお金を使うことに慣れた。 最初は自分への投資は大事!ということで食に使うようになり、 次第にPCや椅子やベッドなどなど自分が直接使うものにはお金を使うようになってきた。

その中で一番気持ちの変容が大きかったのがソフトウェアへの支払いで、 学生の頃はなんでもフリーないしオープンソースのものでなんとかする、という姿勢でいたものの、 今はお金を出してよいソフトウェアを買って、快適に利用する、というのが当たり前になった。 最初にお金を払ったのはSubsonicで携帯に音楽を自分のサーバーからストリーミングするソフトウェアだった。 学生の時にライセンスを購入したのだけれど、paypalを利用するのもこの時が初めてでとてもそわそわしながら支払ったのをよく覚えている。 他には、windows surfaceを購入したときに買ったdrawboard pdfや、 最近はresearchat.fmのsohさんオススメのaffinity designer(adobe illustratorみたいなもの)を購入して便利に利用している。

しかしサブスクリプションに対しては未だに抵抗があって(お金が垂れ流しになっている感覚があるので)、spotifyとnordvpnには加入しているが、これ以上はあまり増やしたくない。 逆に、Googleのサービスを始め、無料でソフトウェアを使うことに関しても抵抗を感じはじめており、いつサービスをやめられるかわからないことや自分のデータを勝手に利用されていることへの気持ち悪さがある。 買い切りソフトウェアだけですっきり済ませて生活したいという気持ちがつよい今日この頃。

特にオチもまとめもないです。