使用赋值运算符进行分配内存不需要的std::vector复制

6

当有两个具有原始数据类型的std::vector实例,大小和容量相同时,是否保证通过复制赋值运算符进行复制不会重新分配目标向量?

例如:

const int n = 3;

std::vector<int> a, b;

// ensure defined capacity
a.reserve(n);
b.reserve(n);

// make same size
a.resize(n);
b.resize(n);

// set some values for a
for (int i = 0; i < n; i++)
{
    a[i] = i;
}

// copy a to b: allocation free?
b = a;

我只在cppreference.com上找到了"否则,*this拥有的内存可能会在可能的情况下被重用"(自C++11起)。我希望看到的是“必须”而不是“可能”。
如果对于更一般的情况(例如“相同大小足够”)应该有一个积极的答案,那就更好了。
如果没有保证,这种情况可能是回答Copying std::vector: prefer assignment or std::copy?的答案,当使用std::copy时会更好。

如果有足够的数据可用(足够大的“reserve”足以,无需对目标进行“resize”),那么我会认为这是一种事实上的保证。此时,任何仍在进行分配的编译器都不值得考虑安装。另一方面:您是否需要保留b的内容?否则,“move”赋值或交换数据可能更有趣... - Aconcagua
我很难想象在当前 capacity() 没有超过时会有任何分配的实现。另一方面,为什么标准会做出这样的保证呢?看起来没有必要。 - ixSci
在我的具体使用情况下,交换确实可以起作用,谢谢你的提示。 - Pedro
但我必须指出,从软件架构的角度来看,交换并不是一个理想的解决方案,因此复制仍然是更合适的解决方案。它不是关键的性能部分。 - Pedro
为什么要使用 b.resize(n)?同时将 a[i] = i 替换为 a.emplace_back(i),这样你也可以省略 a.resize(n) - Goswin von Brederlow
问题只是关于复制。其他都是无聊的示例代码。我在发布之前实际上已经使用了push_back,然后认为resize对于两者都更好看,甚至在视觉上显示ab的情况相同。这与实际问题无关。 - Pedro
1个回答

6

标准不能保证没有分配。根据C++11标准b = a;的效果就像b.assign(a.begin(), a.end())(如果有多余的b元素,则被销毁),其结果是"用 [a.begin(), a.end()) 的副本替换 b 中的元素"。没有关于分配的说明,但在C++20标准(也许更早)中,我们有一个额外的声明:"使得所有指向 b 元素的引用、指针和迭代器失效"。这意味着可能会进行分配,并且在这些保证中没有提到capacity()来防止它在您的特定情况下发生。

另一方面,实际上,如果已经有足够的内存,为什么要重新分配内存呢?


我不知道为什么会这样做,而且我同意,实际上,任何明智的编译器都不会重新分配。但由于我不能百分之百确定,我更喜欢在使用std::copy时进行大小相等检查。 - Pedro
@Pedro,我不知道你有什么要求,但对我来说,这似乎是毫无必要的复杂化,而且没有理由。但是嘿,这是你的代码。 - ixSci
我希望能够保证在这个复制操作中不会发生任何重新分配,因为整个运行时处理都保证是无分配的。而且这段代码将被多个编译器编译为多个平台。如果我可以用另一行代码+一个简单的检查/断言来替换一行代码,我宁愿这样做,而不是问自己是否应该检查所有不同的构建。但我完全理解你的观点:实际上,这对于什么都没有意义 - 除了心安。 :-) - Pedro
@Pedro 如果你必须保证没有动态分配,我不确定 std::vector 是否是正确的选择。 - MatG
对于我的使用情况,我认为是这样的,因为我需要在运行时极少地支持更改元素数量(由单独的方法触发重新配置),而std::vector很方便。但实际处理方法应该不涉及动态分配。 - Pedro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接