使用 memset 初始化包含数组的结构向量
Posted
技术标签:
【中文标题】使用 memset 初始化包含数组的结构向量【英文标题】:using memset to initialize vector of structure which contains array 【发布时间】:2016-05-08 13:45:55 【问题描述】:我有以下结构
struct a
int array[20]
int array2[45]
我已经创建了这个结构的向量
vector<a> vec;
我用过这个 vec。现在我想初始化(设置向量元素中对象内的所有数组值)为零。我该怎么办?
【问题讨论】:
是什么阻止了您阅读std::vector
文档?你为什么决定使用memset
?得出这个结论后你做了什么尝试?
@LightnessRacesinOrbit:std::vector 通常会为其包含的对象调用默认构造函数。因为这个结构只是内置类型,所以元素不会被零初始化。
@MartinBonner:是的,我知道这一点。 OP 需要进行一些研究以找出如何将他的元素归零。这个问题展示了零研究工作。我正在尝试提示 OP进行一些研究。
为什么你认为他没有?使用零初始化对象的副本构造向量、为结构提供默认构造函数和 memset 都是可行的方法 - memset 可能是最好的。
@MartinBonner std::vector
将对其元素进行值初始化,而不是默认初始化它们。所以它们将被零初始化。您可以通过阅读一些文档来了解这一点。
【参考方案1】:
阅读 cmets,您尚未显示填充向量的代码。现在您想重用存储而不是创建一个新存储,并且您想重新初始化它。
任何 C++ 容器的任何算法的规范答案都可能在标准算法中找到。在这种情况下,std::fill。以您喜欢的方式初始化您的结构,并将其复制到您的向量中。沿着这些思路:
a A = 0;
std::fill(vec.begin(), vec.end(), A);
如果您想说这还不够快,请检查一下。我想你会发现它非常有效。上面的代码绝对安全,适用于fill
的任何正确初始化的参数。我怀疑它是否可以在不对a
的实现做出一些假设的情况下做得更快。
【讨论】:
【参考方案2】:事实证明,这是一个比最初看起来更有趣的问题。
tl;dr:如果您使用的是 C++03 或更高版本的编译器,则无需费心。
您需要了解value initialization 和default initialization 之间的区别。基本上值初始化会将所有元素设置为零,而默认初始化将使它们完全独立。如果结构的任何默认元素(递归)具有用户定义的默认构造函数,则值和默认初始化都会调用它。
请注意,值初始化远比memset
为零好,因为
memset
可能会在您的实现中这样做,但不能保证这样做。
创建带有 n 个元素的向量的正常方法是调用:
std::vector<a> vec(n);
C++98
这会调用
std::vector<a>::vector(size_type count,
const T& value = T(),
const Allocator& alloc = Allocator());
value
对象将被默认构造,您需要以某种方式初始化元素。做到这一点的最佳方法是提供要复制的正确值初始化值。所以:
const static a azeroed; // Because this is static, it will be value initialized
std::vector<a> vec(20,azeroed);
技术说明:C++98标准不包含“值初始化”一词,但azeroed
的初始化是相同的。
C++03
调用了相同的向量构造函数,但从 C++03 开始,value
参数是值已初始化(所以花园里的一切都是美好的)。
C++11
打电话给
std::vector<a>::vector(size_type count);
哪个值直接初始化元素。
C++14
来电
std::vector<a>::vector(size_type count, const Allocator& alloc = Allocator());
(基本上,他们意识到他们忘记了分配器参数)。这里有一个非常细微的区别,因为元素是通过调用Allocator::construct
构造的,虽然默认分配器会初始化元素,但可以提供一个自定义版本,而不是(参见this answer) .如果你这样做,你几乎肯定知道你在做什么。
结论
除非你使用的是真正的 C++98 编译器,否则你不需要调用 memset 向向量构造函数提供显式初始化值比调用 memset 更安全。 memset 可能无法正确初始化非整数内置值(尽管它可能会)。 memset 肯定会破坏任何合适的构造函数。这是一个巨大的维护隐患。如果维护程序员更改结构使其不再是 POD,代码仍将编译 - 它只会做错事。 只需为结构体提供一个适当的默认构造函数,就有很多话要说,这样您就不必担心是否有任何元素已初始化,即使您有一个本地副本。【讨论】:
这样做的问题是,如果你改变了类型,可能会使结构不再是 POD,这只会默默地继续将所有内容归零,这可能是一个严重的错误。我发现其中一个曾经在生产中造成多年的间歇性崩溃,使客户损失了数千美元。更喜欢 C++ 中的类型安全解决方案,尤其是在教学时。 这不是一个很好的例子。所示的初始化导致所有元素的初始化数据为零,而无需调用memset
。
@juanchopanza: 章节和诗句好吗?给定结构的定义,默认构造 不会 零初始化它。 (还是我弄错了?)
正如我在另一条评论中所说,std::vector
值初始化元素。
@MartinBonner,对于特定的参考,[vector.cons] 表示默认插入的元素。 [container.requirements.general] 将其澄清为allocator_traits<A>::construct(m, p)
。从那里,[allocator.traits.members] 将其转换为a.construct(p, std::forward<Args>(args)...)
(因为这是默认分配器),[allocator.members] 说这是::new((void *)p) U(std::forward<Args>(args)...)
,这是当 args 包为空时的值初始化。这有点迂回,并且可以随着分配器而改变,但几乎在所有情况下都应该如此。以上是关于使用 memset 初始化包含数组的结构向量的主要内容,如果未能解决你的问题,请参考以下文章