【问题标题】:Does C++11 mandate that a vector<int> zeros the elements in resize()? [duplicate]C++11 是否要求 vector<int> 将 resize() 中的元素归零? [复制]
【发布时间】:2013-03-31 18:46:46
【问题描述】:

这个问题是关于 new[] int 和 new [] int() 在语义和性能上的差异,以及在向 allocator_traits::construct 添加 ctor 参数的完美转发时可能无意中创建的从第一个措辞到第二个措辞的变化()。这个问题不涉及一个非常明显的问题,即默认 ctor 在由向量的 resize() 构造的所有新元素上运行。

对我来说,在调整大小时清除内置类型向量的元素似乎是一种浪费。但是 VS2012 的实现使得 resize(n) 以及因此带有 count 参数的构造函数实际上将分配的值数组设置为 0。

我还在标准中找到了对此的支持,(http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2012/n3485.pdf) 但我认为它到达那里可能是一个错误,因为它依赖于最近涉及完美转发的条款:

第 507 页:

template <class T, class... Args>
static void construct(Alloc& a, T* p, Args&&... args);

5 效果:调用

::new (static_cast<void*>(p)) T(std::forward<Args>(args)...).

并且由于 new int() 必须根据同一文档第 191 页上的第 11 条将值设置为 0,因此向量中的浪费实现是正确的。

问题是标准提交是否真的希望构造调用的空参数包导致行为从默认构造更改为基本类型的值构造。

【问题讨论】:

  • 有一种方法可以在 C++11 中创建 intvector 而无需将其初始化为 0。我会在答案中展示如何,但我不能因为这个问题已经被关了。我会把答案放在重复的问题中,但我的答案没有解决这个问题,因为它确实不是这个问题的重复。我会将代码放在此评论中,但它会不可读。如果您提出一个新问题,并且我可以在它作为副本关闭之前解决它,我将展示如何在 C++11 中创建这样的向量。
  • 我想知道这一点,但请注意,使用分配器不会削减它,因为我必须将向量传递给采用“香草”向量的(非模板化)函数
  • 好的,分配器就是我要给你看的。在 C++03 中你不能使用分配器来做到这一点,但在 C++11 中你可以。

标签: c++ performance vector c++11


【解决方案1】:

不,这不是一个错误。

标准的先前版本让resize(n) 创建一个元素,然后将其复制到向量中的所有新位置。新的措辞是故意允许不可复制但可构造的类型。

【讨论】:

  • C++11 对容器中对象的具体要求是什么? (它曾经是 CopyConstructable 和 CopyAssignable,但那是在移动语义之前。)
  • 我认为这取决于容器的类型和您要执行的操作。 :-( 对于向量,最小值似乎是 MoveConstructible 和 MoveAssignable。对于基于节点的容器,我们现在也有 EmplaceConstructible(这可能是一个较弱的要求)。
  • 我曾希望没有默认参数的新 resize() 重载旨在能够在不初始化元素的情况下构造 vector,但当然你的用法也很有趣。
  • @Bengt - 不初始化整数将不能移植到整数具有陷阱值的(极少数)系统。您还可以选择使用reserve 来分配空间,然后再添加值。
  • @BoPersson reservepush_back 的问题是,在(诚然非常罕见的)性能成为问题的情况下,使用它们通常比使用不必要的元素创建元素更昂贵初始化。
【解决方案2】:

容器永远不会持有未初始化的对象是一个不变量 目的。这意味着任何增加 容器必须以某种方式初始化所有新元素。 这是一个特性,而不是一个缺陷——访问未初始化的 values 是未定义的行为,您无法重新分配(或 插入)如果某些值未初始化。例如:

std::vector<int> v;
v.resize( 20 );
v.insert( v.begin(), 1 );

如果resize 最后一行将导致未定义的行为 没有初始化它创建的元素。

【讨论】:

  • 但你可以定义struct A {int a; A(){}}; 并制作一个向量......
  • 不合法:-)。这将是未定义的行为。但有趣的是:编译生成一个复制构造函数,即使使用它可能会导致未定义的行为。
  • 问题是对于 int 默认构造函数被定义为什么都不做。当然 resize() 应该调用新元素的默认构造函数,但现在没有办法说我不在乎最初的值是什么,因为我会在阅读它们之前编写它们。
  • @BengtGustafsson 你不必说出来。如果您在阅读它们之前先编写它们,那么将它们初始化为0 不会伤害您。
  • 这确实伤害了我的表现。 C++ 容器应该“和数组一样快”。我认为这是一个大问题。这里的重点是 int 的默认 ctor 被定义为什么都不做,而在某些上下文中调用的“特殊”构造函数如果使用空尾括号将值设置为 0。
猜你喜欢
  • 2012-08-24
  • 2011-12-15
  • 2014-01-28
  • 2012-05-03
  • 1970-01-01
  • 2016-03-30
  • 1970-01-01
  • 1970-01-01
  • 2020-08-06
相关资源
最近更新 更多