【问题标题】:Elegant avoiding of value-initialization of vector elements in future C++?在未来的 C++ 中优雅地避免向量元素的值初始化?
【发布时间】:2016-06-28 13:32:26
【问题描述】:

当元素被默认插入std::vector<T>的实例中时,它们默认值初始化。我经常使用多线程高性能代码,在这种情况下,大型数组的这种值初始化可能代表不可接受的顺序瓶颈。

如果在并发代码中,基于reserve()push_back()/emplace_back() 的典型方法是没有用的。我通常会选择以下选项之一:

  1. T定义一个空的默认构造函数,
  2. 具有空construct() 成员函数的自定义分配器的定义和使用。

但是,这两种解决方案都远非优雅,而且也有缺点。前者不能用于T为POD类型,如double。后者需要 C++ 标准库的给定实现来支持相对较新的DefaultInsertable 概念。此外,自定义分配器的定义非常繁琐。

是否有可能在 C++ 的未来有一些直接的方法来“关闭”这种默认插入/值初始化?

更新

Mayebe,我应该简单地问一下,对于算术类型,是否可以避免 零初始化 向量的默认插入元素。

【问题讨论】:

  • 不。当一个类的实例被构造时,它就被构造了。除了构造一个类的新实例之外,别无选择。这涉及到语言的基本完整性。您将不得不使默认构造函数尽可能轻量级。
  • @SamVarshavchik 好的,这对于课程来说是合理的。但是,例如,对于双精度向量,我不需要将元素归零。
  • 一定要用矢量吗?你总是可以只是malloc()你需要什么。
  • 可以使用std::vector + 自定义分配器或使用适当的 Boost 向量变体。在某个地方有一个骗子(比thisiirc 更好),但我现在没有时间搜索。
  • 这样的分配器已准备好在我正在考虑的欺骗中使用,因此无需重做。如果您不想要 Boost,那可能是最简单的方法。一些重构必须在 bc 发生。正常std::vector<T> 必须值初始化 bc。标准是这样说的,没有办法。我不知道委员会正在讨论更简单的替代方案。

标签: c++ vector resize value-initialization


【解决方案1】:

Vector 不太适合您的需求。它支持调整大小和意外复制,这在多线程环境中都没有意义。

写一个简单的容器:

 template<class T,class Storage=std::aligned_storage_t<sizeof(T),alignof(T)>{
 struct buffer{
   static_assert(std::is_pod<T)::value, "pod only");
   std::size_t count;
   std::unique_ptr<Storage[]> storage;
 };

使用容器式的 begin/end/front/size/[]/empty 等填充它。

让它只移动。

使用零规则(=default)。

给它一个explicit buffer(std::size_t) ctor,它会创建未初始化的内容。

混合一些 span/array_view 类型,这应该适合你的需要。

也许有emplace(size_t,Args&amp;&amp;),它为您提供了{} 的新位置。

【讨论】:

  • 这是另一种选择,需要重构现有代码。我想最好的方法是自定义分配器,它可以保证对齐并防止 POD 类型的零初始化。将尝试在 cmets 中找到 Baum mit Augen 提到的那个。
  • 我的全部观点是,在我看来,这样的分配器将是 C++ 标准库的一个很好的扩展 :)
  • @dan 我试图解决你的问题。如果您想为标准化提出一些建议,那么 SO question 不是一个好的论坛。
  • 谢谢,有更多的选择总是好的。而且我会更多地了解整个 C++ 标准化过程。
猜你喜欢
  • 1970-01-01
  • 2011-07-10
  • 2010-11-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 2017-07-01
相关资源
最近更新 更多