如何将整数结构初始化为零?

Aff*_*Owl 5 c++ c++11

确保以下大型结构的整数初始化为0的最佳方法是什么?

struct Statistics {
    int num_queries;
    int num_respones;
    // ... 97 more counters here
    int num_queries_filtered;
}
Run Code Online (Sandbox Code Playgroud)

我想避免必须检查每个地方这个结构初始化,以确保它是初始化值Statistics s();而不是默认初始化Statistics s;.

Statistics s;     // Default initialized by accident here
s.num_queries++;  // Oh no, this is a bug because it wasn't initialized to zero
Statistics s2{};  // Correctly value initialized
s2.num_queries++; // Successful
Run Code Online (Sandbox Code Playgroud)

建议1 - 使用memset,但这感觉就像一个黑客,我们利用值初始化发生相当于0填充数据结构:

struct Statistics {
    Statistics() { memset(this, 0, sizeof(*this)); }
    // ... counters here
}
Run Code Online (Sandbox Code Playgroud)

建议2 - 使用构造函数初始化列表,但这很麻烦,当人们将来添加新计数器时,他们可能忘记在构造函数中对它们进行零初始化:

struct Statistics {
    Statistics() : num_queries(0), num_respones(0), /* ... */, num_queries_filtered(0) {}
    // ... counters here
}
Run Code Online (Sandbox Code Playgroud)

建议3 - 强制值初始化发生如下:

struct StatisticsUnsafe {
    // ... counters here
}

struct Statistics : public StatisticsUnsafe {
    Statistics() : StatisticsUnsafe() {}
}
Run Code Online (Sandbox Code Playgroud)

你觉得最好的方法是什么?你有其他选择吗?

编辑我想澄清一下,在我的实际代码中,每个计数器都有一个有意义的名称,例如"num_queries_received","num_responses"等.这就是为什么我不选择使用"计数器"形式的向量或数组的原因[100]"

EDIT2将示例更改Statistics s2();Statistics s2{};

Jar*_*d42 7

从C++ 11开始,您还可以:

struct Statistics {
    int counter1 = 0;
    int counter2 = 0;
    // ... more counters here
    int counter100 = 0;
};
Run Code Online (Sandbox Code Playgroud)


Jer*_*fin 5

除非你有一个相当具体的理由否则,你的第一选择应该是std::vector,例如:

std::vector<int> Statistics(100);
Run Code Online (Sandbox Code Playgroud)

这将自动归零所有内容.您可以counter将数组中的个人称为:

++Statistics[40];
Run Code Online (Sandbox Code Playgroud)

...这将递增41 项目(第一个是Statistics[0]).

如果大小确实固定为100(或者您在编译时知道的其他数字),您可能更愿意使用std::array:

std::array<int, 100> Statistics;
Run Code Online (Sandbox Code Playgroud)

这可能是一个快一点,通常采用的是(小)更少的内存,但固定尺寸(而用的std::vector,你可以使用push_back,erase等等,添加和删除的项目).

鉴于编辑过的问题(对象真的不像数组一样),我可能会考虑一些不同的东西,可能是这样的:

template <class T>
class inited {
    T val;
public:
    inited(T val=T()) : val(val) {}
    operator T() const { return val; }
    operator=(T const &newval) { val = new_val; }
};

struct Statistics { 
    inited<int> sum;
    inited<int> count;
    inited<double> mean;
};
Run Code Online (Sandbox Code Playgroud)

然后a inited<T>总是被初始化为某个值 - 如果你愿意,你可以指定一个值,如果你没有指定任何值,它使用值初始化(对于算术类型将给出零,对于指针类型给出空指针,或者对定义一个的类型使用默认构造函数.

既然它定义了一个operator T和一个operator=,你仍然可以像往常一样分配给元素/从元素中分配:

Statistics.sum = 100;
Statistics.count = 2;
Statistics.mean = static_cast<double>(Statistics.sum) / Statistics.count;
Run Code Online (Sandbox Code Playgroud)

您可能更喜欢使用单个:

operator T&() { return val; }
Run Code Online (Sandbox Code Playgroud)

相反.这既支持读取和写入(如上所述),也支持复合赋值运算符(例如,+=-=).

  • 在我的实际代码中,每个计数器都有一个有意义的名称,如"num_queries"或"num_responses"而不是"counter1"或"counter2".因此,使用计数器[42]是没有意义的.充其量,我可以定义一个从索引映射到枚举名称的枚举,并使用它来索引到数组.所以这是另一种选择,但是为了获得0初始化似乎很麻烦. (2认同)