指向向量第一个元素的指针与该向量的 back_inserter() 有何不同?

How differ a pointer to first element of a vector vs back_inserter() of that vector?

我知道back_inserter是一个容器“适配器”,但它是什么意思呢?如果我以函数 std::copy() 为例,它将向量 TO 复制的第三个参数输出 iterator/pointer 作为参数,那么我应该给出该向量的 back_inserter 而不是 last iterator

#include <vector>
#include <algorithm>
#include <stdio.h>

using namespace std;

int main(){
    vector<int> vec1 = {1,2};
    vector<int> vec2 = {3,4};
    copy(vec2.begin(), vec2.end(), back_inserter(vec1)); //back_inserter used to enhance memory allocation for 2 new elements?
    for(auto i:vec1){
        printf("%i\n", i);
    }
}

工作正常,但是这个版本没有:

#include <vector>
#include <algorithm>
#include <stdio.h>

using namespace std;

int main(){
    vector<int> vec1 = {1,2};
    vector<int> vec2 = {3,4};
    copy(vec2.begin(), vec2.end(), vec1.end()); // the same pointer as gives back_inserter but without any fancy allocation and therefor crash?
    for(auto i:vec1){
        printf("%i\n", i);
    }
}

现在我只复制了矢量的最后一个 iterator/pointer。那么 back_inserter 容器适配器的作用是什么?现在对我来说,它只为新元素分配 space 的工作,而“仅”最后一个指针是不够的。我可以通过 malloc 手动放大 vector/container 吗?

std::copy 会将元素从一个迭代器范围复制到另一个已经存在元素的迭代器范围。它不会创建新元素。

std::back_inserter 将允许使用 copy(以及其他需要元素存在的算法)将元素添加到支持 push_back.

的现有容器中

您可以在 copy 之前使用 resize 手动扩展 vec1 来为新元素分配 space,但这会增加最好避免的复杂性(因为您必须知道将向量调整到多大,以及开始复制到什么迭代器)。

back_inserter 处理几件事:

  • 每次写入以存储一个值(即 *it =)时,它都会增长 vector,就像您调用 push_back 一样;如果 vectorsize() 已经等于它的 capacity(),那么这意味着它需要为扩大后的内容分配一个新的内存区域,并将现有内容复制过来,然后添加新元素
  • 等同于 push_back,它确保 vectorsize() 继续反映存储的元素数量

end() 迭代器表示当前存储元素末尾后一个位置,如 size() 所示,但未指定实现。通过它写入是未定义的行为(即 *vec1.end() = ...)。

Can I do a manual job via malloc to enlarge that vector/container?

否 - 向量是用 new 分配的 - 而不是“C”库函数 malloc - 你不能将两者混用。但是,您可以通过两种方式手动增加 vector 的内存:

vec1.resize(4);    // then size() == capacity() == 4, [2] and [3] are 0

vec1.reserve(4);   // then size() == 2, capacity() == 4,
                   //      [2] and [3] are unspecified

这是未定义的行为,没有理由实际尝试使用它,但出于好奇:在某些实现中,如果您像上面那样调用 reserve()end() 可能 实际上被实现为指向 [2] 的指针,在这种情况下,您的 copy(..., end()) 可能会如您希望的那样巧合地写入 [2][3],但是尽管现在存储了 4 个元素,它仍然会将 size() 的值保留在 2。如果您事先调用 resize(4) 而不是 reserve(),那么 size() 将 return 4,那么 copy(..., end()) 将错误地覆盖不存在的元素 [4][5]。因此,在任何情况下都无法正常工作。

STL 设计有 3 个主要概念:

  • 容器
    • 保留元素
    • 了解about/create 迭代器
    • 不了解通用算法。
  • 迭代器
    • 引用一个元素(或末尾),可以修改元素
    • 不了解算法
    • 不知道它们的元素所在的容器*(因此无法修改容器的大小或其他)
  • 算法
    • 通常使用迭代器
    • 了解容器

A back-inserter,然而,看起来和行为都像一个迭代器,就算法而言,它 一个迭代器。但是作为一个容器适配器,它有一个容器的引用并且可以在你写入它的迭代器接口时修改它(通过“push_back”)。这允许算法以迭代器的形式不透明地写入它,并且(在没有意识到的情况下)也能够修改容器。

(*) 有时,迭代器的调试实现会了解容器,但这是一个内部实现细节,普通 public 接口无法使用。