区分两个零参数构造函数的惯用方式

我有一个这样的班级:

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{});之类的no-init构造函数。

我愿意接受不涉及创建哑类或以某种方式更有效的解决方案,等等。

h3251300 回答:区分两个零参数构造函数的惯用方式

您已经拥有的解决方案是正确的,并且正是我要查看您的代码时想要的解决方案。它尽可能高效,清晰和简洁。

,

如果构造函数主体为空,则可以将其省略或默认设置:

struct event_counts {
    std::uint64_t counts[MAX_COUNTERS];
    event_counts() = default;
};

然后默认初始化 event_counts counts;将使counts.counts保持未初始化状态(默认初始化为no-op),而值初始化 {{1 }}将值初始化event_counts counts{};,有效地用零填充。

,

我喜欢您的解决方案。您可能还考虑了嵌套的struct和static变量。例如:

struct event_counts {
    static constexpr struct uninit_tag {} uninit = uninit_tag();

    uint64_t counts[MAX_COUNTS];

    event_counts() : counts{} {}

    explicit event_counts(uninit_tag) {}

    // more stuff

};

使用静态变量未初始化的构造函数调用似乎更方便:

event_counts e(event_counts::uninit);

您当然可以引入一个宏来保存键入内容,并使之更具有系统性

#define UNINIT_TAG static constexpr struct uninit_tag {} uninit = uninit_tag();

struct event_counts {
    UNINIT_TAG
}

struct other_counts {
    UNINIT_TAG
}
,

我认为枚举比标记类或布尔值更好。您无需传递结构实例,调用者就可以清楚地知道要获得哪个选项。

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 {
    enum NoInit { NO_INIT };
    uint64_t counts[MAX_COUNTERS];

    event_counts() : counts{} {}
    explicit event_counts(NoInit) {}
};

那么只有两种创建实例的方法:

event_counts e1{};
event_counts e2{event_counts::NO_INIT};
,

您可能想为您的课程考虑一个两阶段初始化

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(bool initCounts) {
        if (initCounts) {
            std::fill(counts,0);
        }
    }
};

当您使用event_counts(false)时,编译器将足够聪明,可以跳过所有代码,而您可以确切地说出您的意思,而不是使类的界面变得很奇怪。

,

我只想使用一个子类来节省一些输入:

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{}) {}
};

您可以通过将未初始化的构造函数的参数更改为boolint之类的东西来摆脱虚拟类,因为它不再需要助记符了。

您还可以交换继承关系,并使用其答案中建议的默认构造函数(如Evg)定义events_count_no_init,然后将events_count作为子类:

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{} {}
};
本文链接:https://www.f2er.com/3091980.html

大家都在问