【问题标题】:How differ a pointer to first element of a vector vs back_inserter() of that vector?指向向量第一个元素的指针与该向量的 back_inserter() 有何不同?
【发布时间】:2023-04-07 06:15:01
【问题描述】:

我知道back_inserter 是一个容器“适配器”,但它是什么意思?如果我以函数std::copy() 为例,它将向量的第三个参数输出迭代器/指针复制,那么我应该给出该向量的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);
    }
}

现在我只给出了要复制的向量的最后一个迭代器/指针。那么back_inserter 容器适配器的作用是什么?现在对我来说,它只为新元素分配空间,而“仅”最后一个指针是不够的。我可以通过malloc 进行手动工作以放大该矢量/容器吗?

【问题讨论】:

    标签: c++ vector iterator adapter


    【解决方案1】:

    STL 设计有 3 个主要概念:

    • 容器
      • 保持元素
      • 了解/创建迭代器
      • 不了解通用算法。
    • 迭代器
      • 指一个元素(或结尾),并且可以修改元素
      • 不懂算法
      • 不知道它们的元素所在的容器*(因此无法修改容器的大小或其他)
    • 算法
      • 通常使用迭代器
      • 不了解容器

    然而,back-inserter 的外观和行为类似于迭代器,就算法而言,它是 一个迭代器。但是作为一个容器适配器,它也有一个对容器的引用,并且可以在你写入它的迭代器接口时修改它(通过“push_back”)。这允许算法作为迭代器不透明地写入其中,并且(没有意识到)也能够修改容器。

    (*) 迭代器的调试实现有时会知道容器,但这是普通公共接口无法使用的内部实现细节。

    【讨论】:

    【解决方案2】:

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

    std::back_inserter 将允许使用copy(和其他需要元素存在的算法)将元素添加到支持push_back 的现有容器中。

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

    【讨论】:

      【解决方案3】:

      back_inserter 负责几件事:

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

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

      我可以通过 malloc 进行手动工作以放大该向量/容器吗?

      否 - 向量分配有 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],但尽管存在size() 值仍然会保留在2现在正在存储4 元素。如果您事先调用了resize(4) 而不是reserve(),那么size() 将返回4,那么copy(..., end()) 将错误地覆盖不存在的元素[4] 和[5]。因此,在任何情况下都无法正常工作。

      【讨论】:

        猜你喜欢
        • 2011-08-04
        • 1970-01-01
        • 2011-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-06
        • 2022-01-21
        相关资源
        最近更新 更多