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

时间:2014-10-09 19:25:20

标签: c++ c++11

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

struct Statistics {
    int num_queries;
    int num_respones;
    // ... 97 more counters here
    int num_queries_filtered;
}

我希望避免必须检查每个位置此结构已初始化,以确保使用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

提案1 - 使用memset,但这感觉就像一个黑客,我们利用值初始化发生的等价于0填充数据结构:

struct Statistics {
    Statistics() { memset(this, 0, sizeof(*this)); }
    // ... counters here
}

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

struct Statistics {
    Statistics() : num_queries(0), num_respones(0), /* ... */, num_queries_filtered(0) {}
    // ... counters here
}

提案3 - 强制值初始化按如下方式进行:

struct StatisticsUnsafe {
    // ... counters here
}

struct Statistics : public StatisticsUnsafe {
    Statistics() : StatisticsUnsafe() {}
}

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

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

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

5 个答案:

答案 0 :(得分:7)

从C ++ 11开始,你也可以这样做:

struct Statistics {
    int counter1 = 0;
    int counter2 = 0;
    // ... more counters here
    int counter100 = 0;
};

答案 1 :(得分:5)

除非您有相当具体的理由不这样做,否则您的首选应该是std::vector,例如:

std::vector<int> Statistics(100);

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

++Statistics[40];

...这会增加41 st 项目(第一项是Statistics[0])。

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

std::array<int, 100> Statistics;

这可能会更快一点,通常使用(少)内存,但修复了大小(而使用std::vector,您可以使用push_backerase等,添加和删​​除项目。)

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

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

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

由于它定义了operator Toperator=,您仍然可以像往常一样分配到/来自元素:

Statistics.sum = 100;
Statistics.count = 2;
Statistics.mean = static_cast<double>(Statistics.sum) / Statistics.count;

您可能更喜欢使用单曲:

operator T&() { return val; }

相反。这既支持读写又支持(如上所述),还支持复合赋值运算符(例如+=-=)。

答案 2 :(得分:3)

您是否考虑为每个数据成员编写初始化程序?

struct Statistics {
  typedef int counter_t;

  counter_t counter1 = 0;
  counter_t counter2 = 0;
  // ... more counters here
  counter_t counter100 = 0;
};

请注意,如果您包含此类初始值设定项,则该结构不再是聚合,因此无法通过支持列表使用aggregate initialization初始化该结构。这种类型是否重要很难说。

答案 3 :(得分:3)

嗯,你当然可以这样做:

struct Statistics {
    int counter1 = 0;
    int counter2 = 0;
    // ... more counters here
    int counter100 = 0;
};

这在c ++ 11中完全有效。但问题是,你真的需要这个吗?使用矢量不是更方便吗?

struct Statistics {
    std::vector<int> counters = std::vector<int>(100, 0);
};

如果vector不是一个选项,你可以在构造函数中做一些魔术:

struct Statistics {
    int counter1;
    int counter2;
    // ... more counters here
    int counter100;

    Statistics() {
        for (int * i : {&counter1, &counter2, ..., &counter100 }) {
            *i = 0;
        }
    }
};
Statistics s;
s.counter2; // now stores 0 or anything you like.

答案 4 :(得分:0)

以下是C的方式:

#include <assert.h>
#include <cstring>
#include <type_traits>

struct Statistics {
  int counter1;
  int counter2;
  int counter3;
  int counter4;
  // maybe more //
  Statistics() {
    // checks whether Statistics is standard-layout
    // to be sure that memset won't break it
    static_assert(
        std::is_standard_layout<Statistics>(),
        "Someone broke Statistics, can't use memset to zero it.");
    // initializes hole Statistics's memory by zeros
    memset(this, 0, sizeof(Statistics));
  }
};

// Here is a way how to check Statistics
void assert_Statistics() {
  Statistics s;
  int* ptr   = reinterpret_cast<int*>(&s);
  int  count = sizeof(Statistics) / sizeof(int);
  for (int i = 0; i < count; ++i) {
    assert(*(ptr++) == 0);
  }
}

int main()
{
  Statistics s;
  assert_Statistics();
}