LoginSignup
0
2

More than 3 years have passed since last update.

死ぬときに遺言を実行してくれるオブジェクト(C++)

Posted at

Testate.h
(Testate=遺言を残した状態を表す形容詞)

概要

みなさん、このスコープを抜けたときに〜したいとか、このインスタンスが死ぬときに〜したいとかいう場面は多いんじゃないかと思います。
スコープだと書き忘れによるバグが心配ですし、インスタンスの場合はデストラクタに書けばいいじゃんと思いがちですが、こんな風にデストラクタとかフィールドが汚れるの嫌じゃないですか?僕は嫌です。
それに、フラグを立てる箇所と回収する箇所が離れてるとバグを生みやすいと思うんですよね。
フラグは立てた箇所に回収処理を書きたいし、何かの後始末はそれが必要になった箇所に書きたいですよね。

class SomeClass {
public:
    ~SomeClass() {
        // このチェックしたくない
        if(isProperlyCreated()) {
            destroy();
        }
        // このフラグ作りたくない
        if(is_opened) {
            close();
        }
    }
private:
    bool is_opened = false;
};

ということで、こちらを使えばスッキリ解決です。

Testate.h
#pragma once

#include <functional>

class Testate
{
public:
    using Will = std::function<void()>;
    Testate(){}
    Testate(Will lastword) {
        leaveWill(lastword);
    }
    void leaveWill(Will lastword) {
        lastwords_.push_back(lastword);
    }
    void expire() { is_expired_ = true; }
    ~Testate() {
        if(is_expired_) return;
        for(auto &&lastword : lastwords_) {
            lastword();
        }
    }
private:
    std::vector<Will> lastwords_;
    bool is_expired_=false;
};

使用例

使用例(クラスメンバー)
#include "Testate.h"

class SomeClass {
public:
    void open() {
        // ...some stuff here to open something
        // and leave a last word
        // `close()` will be executed when this class dies.
        terminator.leaveWill([&](){close();});
    }
private:
    Testate terminator;
};
使用例(スコープ)
{
    Testate onScopeEnd([&](){popSomeThing();})
    pushSomething();
    // do something here

    // `popSomething()` will be executed when exiting this scope.
}
使用例(with_expiration)
{
    Testate if_succeeded([&](){submitSomething();});
    for(auto &&cond: conditions) {
        if(!cond.check()) {
            if_succeeded.expire();
        }
    }
    // when exiting this scope, `submitSomething()` will be executed
    // unless it is not expired.
}

名付けについて

SFPC Summer 2019 in Yamaguchiでの経験と、昔読んだリーダブルコードの記憶が結ついて、ちょうど意味のある(リーダブルコードで言う「カラフルな」)名付けを意識し始めた時期だった。

クラス内に使われている語彙としては以下がある。
- testate : 遺言を残した状態
- will : 望み・遺言
- last word : 遺言・最後の言葉
- expire : (契約・有効期限の)期限切れ
(別にネイティブチェックを受けたわけではなく、辞書とフィーリングでやってしまっているので間違いがあれば教えて欲しい。。。)

もっと機能に寄せて
- ScoredPromiseとか
- Afterwardsとか
- reserveとか
- taskとか
- finallyとか
を名付けに使ってもよかったところかもしれないが、これらは僕の感覚ではあまりカラフルではなく、面白味が少ないと思ってしまう。
名付けで誤解を生んでは本末転倒、という人もいるかもしれないが(そしてそれには同意するが)、そこを保ったままで、どう人の心を動かすのかとか、どう自分の経験や思いをプロダクトに反映するのかという視点は継続して持っていたい。

その他

あとでReactを勉強してから思いましたが、発生と回収を近い位置に書きたいという姿勢はReact hooksのuseEffectに近いかもしれない。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2