如何解决为什么std :: copy要求std :: back_inserter插入具有足够容量的向量中?
参考代码:
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
void print(std::string label,std::vector<int> & arr) {
std::cout << label << ":" << " size: " << arr.size() << " cap: " << arr.capacity() << " [ ";
for (auto elem : arr) {
std::cout << elem << " ";
}
std::cout << " ] " << std::endl;
}
void reserve_dest_use_begin() {
std::vector<int> s_arr = {0,1,2,3,4,5};
print("source",s_arr);
std::vector<int> d_arr;
d_arr.reserve(3);
print("dest",d_arr);
auto min_elems = std::min(s_arr.size(),d_arr.capacity());
std::cout << "copYING FirsT" << min_elems << "3 FROM SOURCE TO DEST" << std::endl;
std::copy(s_arr.begin(),s_arr.begin() + min_elems,d_arr.begin());
print("source",s_arr);
print("dest",d_arr);
}
void reserve_dest_use_back_inserter() {
std::vector<int> s_arr = {0,d_arr.capacity());
std::cout << "copYING FirsT" << min_elems << " ELEMENTS FROM SOURCE TO DEST" << std::endl;
std::copy(s_arr.begin(),std::back_inserter(d_arr));
print("source",d_arr);
}
int main() {
std::cout << "RESERVE DEST ARR. USE BEGIN() TO copY" << std::endl;
reserve_dest_use_begin();
std::cout << "RESERVE DEST ARR. USE BACK_INSERTER() TO copY" << std::endl;
reserve_dest_use_back_inserter();
输出:
RESERVE DEST ARR USE BEGIN() TO copY
source: size: 6 cap: 6 [ 0 1 2 3 4 5 ]
dest: size: 0 cap: 3 [ ]
copYING FirsT 3 ELEMENTS FROM SOURCE TO DEST
source: size: 6 cap: 6 [ 0 1 2 3 4 5 ]
dest: size: 0 cap: 3 [ ]
=============================================
RESERVE DEST ARR USE BACK_INSERTER() TO copY
source: size: 6 cap: 6 [ 0 1 2 3 4 5 ]
dest: size: 0 cap: 3 [ ]
copYING FirsT 3 ELEMENTS FROM SOURCE TO DEST
source: size: 6 cap: 6 [ 0 1 2 3 4 5 ]
dest: size: 3 cap: 3 [ 0 1 2 ]
在两种情况下,目标阵列均具有足够的容量。 cppreference的文档指出:
copies the elements in the range,defined by [first,last),to another range beginning at d_first.
1) copies all elements in the range [first,last) starting from first and proceeding to last - 1. The behavior is undefined if d_first is within the range [first,last). In this case,std::copy_backward may be used instead.
d_arr.begin()
所指向的范围超出了[first,last)
的源范围,但是在提供的示例中,我需要使用std::back_inserter()
进行复制,而不仅仅是提供{{ 1}},尽管基础向量具有足够的容量。
d_arr.begin()
操作是否已优化为仅存储内存块,还是推回了每个元素? cppreference中的注释表示:
std::back_inserter()
但是,我怀疑使用In practice,implementations of std::copy avoid multiple assignments and use bulk copy functions such as std::memmove if the value type is Triviallycopyable and the iterator types satisfy LegacyContiguousIterator.
时,它不会使用std::back_inserter()
进行优化。
总而言之,我有以下问题:
- 当基础向量具有足够的容量时,为什么不能在
memmove
中将d_arr.begin()
用作OutputIt
中的std::copy
? - 是否使用针对批量复制范围进行了优化的
std::back_inserter()
?
编辑:
我认为我从错误的角度提出了这个问题。注释中已经阐明,我要执行的操作是insert()
而不是copy()
。我的特定用例是重复clear()
我的d_arr
并将子向量从s_arr
复制到d_arr
。我试图避免重新分配我的d_arr
。但是,由于清除了d_arr
,并且确实具有足够的容量,但是它没有大小,这意味着没有要复制的元素。相反,我实际上想要做的是将s_arr
的子向量插入d_arr
。
d_arr.insert(d_arr.begin(),s_arr.begin(),s_arr.begin() + min_elems)
解决方法
当基础向量具有足够的容量时,为什么不能在std :: copy中将d_arr.begin()用作OutputIt?
由于目标向量为空,因此std::copy
溢出了该向量(因为任何元素的分配都在空向量的边界之外)。
std :: back_inserter()操作是否已优化为仅记忆
可能是。甚至可以将其优化为更快的速度。
是否使用针对批量复制范围进行了优化的std :: back_inserter()?
给出足够聪明的优化器,是的。
使用适当的vector构造函数比std::copy
更简单。对于代码的阅读者和优化者来说都是如此。
如果我在代码中表达一个简单的向量,也许会有所帮助。
template <class T>
class Vector
{
private:
unsigned int size = 0;
unsigned int capacity = 10;
T* array = new T[10];
public:
void push_back(T const& item) {
if (size >= capacity) {
reserve(capacity * 2);
}
array[size] = item;
++size;
}
void reserve(unsigned int newCapacity) {
if (size > capacity) {
T* const temp = new T[newCapacity];
std::copy(cbegin(),cend(),temp);
delete [] std::exchange(array,temp);
capacity = newCapacity;
}
}
T& operator[](unsigned int i) { return *array[i]; }
// iterators
T* begin() { return array; }
T* end() { return array + size; }
T const* cbegin() const { return array; }
T const* cend() const { return array + size; }
};
您看到的是reserve
确实增加了向量的分配大小,但是并没有改变大小!
在print
中使用基于范围的for循环时,将使用begin
和end
迭代器,它们在内部使用向量的大小。因此,不会访问整个内部数组。
尽管使用自定义终结点(s_arr.begin() + min_elems
)直接写入数组,但具有足够的能力可能不是“非法”,但这根本不是一个好习惯。
编辑:做会改变矢量的大小,是resize
,它在内部看起来像这样
void resize(unsigned int newSize,T const& val = T{}){
if (newSize > capacity) {
reserve(newSize);
}
if (newSize > size) {
std::fill(begin()+size,begin()+newSize,val);
}
size = newSize;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。