std::vector:<T>:resize( n, val ) 是否足以进行初始化?
Is std::vector<T>::resize( n, val ) sufficient for initialisation?
这是一个特定于C++11的问题。假设我已经使用了一个向量std::vector<T> v
并且我想将其调整为n
使用现有值初始化的元素T val
。(典型用例:vector 是被回收的实例的成员)。
以下方法的优缺点是什么,哪种方式最有效?
1) std::vector<T>::resize( n, val )
是否足以进行初始化?
v.clear();
v.resize( n, val );
2)如果不是,那么我认为以下内容是正确的?
v.clear();
v.resize(n);
std::fill( v.begin(), v.end(), val );
3)交换怎么样?
v.swap( std::vector<T>( n, val ) );
为什么不使用专为这项工作设计的界面?
v.assign(n, val);
文档在这里
(4)
std::fill(v.begin(), std::min(v.begin() + n, v.end()), val);
v.resize(n, val);
如果 T 具有合适的赋值行为,至少比构造新赋值行为便宜,则使用 (4)。T = int(赋值和构造相同)和 T = std::string(赋值可能比构造更快,因为它可能能够使用现有缓冲区)就是这种情况。
如果 T 具有相同的分配和构造成本(例如 T = int),那么 (1) 也可以用于清晰而不损失性能。
如果无法分配 T,或者由于某种原因,分配比构造(罕见)成本更高,则使用 (1)
(1) 可以通过使用v.assign(n, val);
来简化(对@Casey的赞美)
我不知道 (4) 使用 assign
在性能方面是否相同。我不知道分配是否会(具有讽刺意味,给定名称)将新元素分配给现有元素,还是重新构建它们。
编辑:对(4)的可能改进,我还没有测试过。它可以避免在矢量容量变化期间复制/移动的开销。
if (n <= v.capacity())
{
std::fill(v.begin(), std::min(v.begin() + n, v.end()), val);
v.resize(n, val);
}
else
{
v.assign(n, val);
}
1)就足够了。(3)也有效。不同之处在于,如果新大小小于当前大小,则 (1) 不会释放内存。(3) 始终分配新的内存块并删除旧内存块。
(2) 通常比 (1) 慢,因为它首先默认构造元素,然后分配它们。如果T
不是默认构造的,它甚至可能无法编译。
让我们分解一下,以显示它们之间的差异。我将使用 n 作为新大小,m 作为旧大小。
1.
v.clear();//keeps the same buffer, but calls the destructor on all the values
v.resize(n, val);//only makes a new buffer if the value is bigger, does no moves.
阿拉伯数字。
v.clear();//keeps the same buffer, but calls the destructor on all the values
v.resize(n);//initializes all the values to default
std::fill( v.begin(), v.end(), val );//initializes all the values again to the new value
3.
v.swap( std::vector<T>( n, val ) );//calls destructor on all values in v, cannot reuse the buffer, initializes all the values to the new value
差异是微妙的,但真实。 1 可以(但不保证)重用缓冲区,这可以节省内存开销。 2 与 1 相同,但执行双重重新初始化。 3 与 1 相同,但它不能重用缓冲区。
我个人认为,在大多数情况下,三者之间的差异太微妙了,无关紧要,而 1 是最易读的。
- 是否可以初始化不可复制类型的成员变量(或基类)
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- 对象初始化中是否允许指向此成员的指针?
- 初始值设定项列表是否只接受使用相同类型的值初始化变量?
- 是否可以防止省略聚合初始化成员?
- 我们是否需要为 C++ 中的多个函数初始化多个模板?
- 为什么需要检查 GLAD 或 GLEW 是否正确初始化?
- C++:带有大括号初始化列表的函数调用表达式 - 标准是否规定在单个元素列表的微不足道的情况下忽略大括号?
- 是否可以使用右值初始化数据成员?
- 当 map 是一个整数数组并且由 operator[] 创建时,它是否初始化其映射类型
- C++,检查当我无法使用 NULL/0 时是否初始化了变量
- make_unique值是否初始化字符数组
- new[] 是否初始化内置数组
- 此零是否初始化数据项
- 检查变量是否初始化
- 是否初始化基元-c++
- std::map 中基元类型的值是否初始化
- Windows 的线程本地存储是否初始化值?
- 不管是否初始化,使用sizeof(p[0])真的无害吗?