c++ - 2つの引数のないコンストラクタを区別する慣用的な方法




performance constructor (5)

私はこのようなクラスを持っています:

struct event_counts {
    uint64_t counts[MAX_COUNTERS];

    event_counts() : counts{} {}

    // more stuff

};

通常、示されているように counts 配列をデフォルト(ゼロ)で初期化します。

ただし、プロファイリングによって特定された特定の場所では、配列が上書きされようとしていることはわかっていますが、コンパイラーはそれを把握するのに十分なほどスマートではないため、配列の初期化を抑制したいと思います。

このような「セカンダリ」ゼロ引数コンストラクタを作成する慣用的かつ効率的な方法は何ですか?

現在、次のように、仮引数として渡されるタグクラス uninit_tag を使用しています。

struct uninit_tag{};

struct event_counts {
    uint64_t counts[MAX_COUNTERS];

    event_counts() : counts{} {}

    event_counts(uninit_tag) {}

    // more stuff

};

次に、 event_counts c(uninit_tag{}); ような非初期化コンストラクターを呼び出し event_counts c(uninit_tag{}); 建設を抑制したいとき。

私はダミークラスの作成を伴わないソリューション、または何らかの方法でより効率的なソリューションなどにオープンです。


あなたが既に持っている解決策は正しく、あなたのコードをレビューしていたかどうかを正確に知りたいと思っています。 それは可能な限り効率的で、明確で簡潔です。


クラスの 2段階の初期化 を検討することをお勧めします。

struct event_counts {
    uint64_t counts[MAX_COUNTERS];

    event_counts() = default;

    void set_zero() {
       std::fill(std::begin(counts), std::end(counts), 0u);
    }
};

上記のコンストラクターは、配列をゼロに初期化しません。 配列の要素をゼロに設定するには、構築後にメンバー関数 set_zero() を呼び出す必要があります。


入力を少し節約するためだけにサブクラスを使用します。

struct event_counts {
    uint64_t counts[MAX_COUNTERS];

    event_counts() : counts{} {}
    event_counts(uninit_tag) {}
};    

struct event_counts_no_init: event_counts {
    event_counts_no_init(): event_counts(uninit_tag{}) {}
};

ニーモニックである必要がないため、初期化しないコンストラクタの引数を bool または int などに変更することにより、ダミークラスを取り除くことができます。

また、継承を入れ替えて、回答で提案されているEvgのようなデフォルトのコンストラクタで events_count_no_init を定義し、 events_count_no_initevents_count_no_init することもできます。

struct event_counts_no_init {
    uint64_t counts[MAX_COUNTERS];
    event_counts_no_init() = default;
};

struct event_counts: event_counts_no_init {
    event_counts(): event_counts_no_init{} {}
};

列挙型は、タグクラスやブールよりも良い選択だと思います。 構造体のインスタンスを渡す必要はなく、呼び出し元からどのオプションを取得するかが明確です。

struct event_counts {
    enum Init { INIT, NO_INIT };
    uint64_t counts[MAX_COUNTERS];

    event_counts(Init init = INIT) {
        if (init == INIT) {
            std::fill(counts, counts + MAX_COUNTERS, 0);
        }
    }
};

次に、インスタンスの作成は次のようになります。

event_counts e1{};
event_counts e2{event_counts::INIT};
event_counts e3{event_counts::NO_INIT};

私はこのようにします:

struct event_counts {
    uint64_t counts[MAX_COUNTERS];

    event_counts() : counts{} {}

    event_counts(bool initCounts) {
        if (initCounts) {
            std::fill(counts, counts + MAX_COUNTERS, 0);
        }
    }
};

コンパイラーは、 event_counts(false) を使用するときにすべてのコードをスキップするのに十分スマートであり、クラスのインターフェースを非常に奇妙にする代わりに、正確に何を意味するかを言うことができます。





constructor