0

0

如何在C++中将一个vector的内容复制到另一个_C++ vector内容复制技巧

裘德小鎮的故事

裘德小鎮的故事

发布时间:2025-09-21 10:37:01

|

731人浏览过

|

来源于php中文网

原创

C++中复制vector内容主要有四种方法:赋值运算符(=)用于全量覆盖,拷贝构造函数用于初始化时复制,std::copy算法配合迭代器可实现灵活的范围复制,insert方法则适合在指定位置插入部分或全部元素。选择哪种方式取决于具体需求,如是否需部分复制、性能要求及内存管理策略。对于性能敏感场景,若源vector不再使用,应优先考虑std::move以避免拷贝开销;若目标vector能预分配空间,std::copy到该空间效率最高;而对于小规模或基本类型vector,各种方法性能差异不大。当涉及复杂对象时,复制开销主要来自元素自身的拷贝构造。此外,部分复制可通过std::copy结合back_inserter或vector的范围构造函数实现,精确控制源范围即可提取子序列。需特别注意的是,当vector存储裸指针时,默认复制仅为浅拷贝,会导致多个vector共享同一对象,引发双重释放或悬空指针问题;正确做法是手动深拷贝或改用智能指针。使用std::unique_ptr的vector不可复制,只能移动,确保所有权唯一;而std::shared_ptr则允许多个vector共享对象,自动管理生命周期,避免内存泄漏。总之,推荐优先使用拷贝构造或赋值运算符进行全量复制,部分复制选用std::copy或insert,性能优化时结合预分配

如何在c++中将一个vector的内容复制到另一个_c++ vector内容复制技巧

在C++中将一个

vector
的内容复制到另一个,核心方法主要有几种:使用赋值运算符(
=
)、拷贝构造函数、
std::copy
算法,或是通过
insert
方法。选择哪种方式,往往取决于你的具体需求,比如是想完全复制,还是只复制部分,以及对性能的考量。

解决方案

在我日常的C++开发中,复制

vector
内容是一个非常常见的操作。最直接、也是我个人最常使用的几种方式,大致可以归纳如下:

1. 使用赋值运算符

=
进行全量复制

这是最简单、最直观的方法。当你已经有一个

vector
,想用另一个
vector
的内容完全覆盖它时,赋值运算符是首选。它会先清空目标
vector
,然后将源
vector
的所有元素逐一拷贝过来。

立即学习C++免费学习笔记(深入)”;

#include 
#include 
#include  // For std::iota

int main() {
    std::vector sourceVec(5);
    std::iota(sourceVec.begin(), sourceVec.end(), 10); // sourceVec: {10, 11, 12, 13, 14}

    std::vector destVec;
    destVec = sourceVec; // 使用赋值运算符复制

    std::cout << "destVec after assignment: ";
    for (int x : destVec) {
        std::cout << x << " ";
    }
    std::cout << std::endl; // Output: 10 11 12 13 14

    // 也可以将一个现有vector的内容赋给另一个
    std::vector anotherVec = {1, 2, 3};
    anotherVec = sourceVec; // anotherVec现在也是 {10, 11, 12, 13, 14}
    return 0;
}

2. 使用拷贝构造函数进行初始化复制

当你声明一个新的

vector
并希望它立即拥有另一个
vector
的全部内容时,拷贝构造函数是自然的选择。

#include 
#include 
#include 

int main() {
    std::vector originalStrings = {"apple", "banana", "cherry"};

    // 方式一:直接初始化
    std::vector copiedStrings(originalStrings);

    // 方式二:使用等号初始化(也是调用拷贝构造函数)
    std::vector anotherCopiedStrings = originalStrings;

    std::cout << "copiedStrings: ";
    for (const auto& s : copiedStrings) {
        std::cout << s << " ";
    }
    std::cout << std::endl; // Output: apple banana cherry
    return 0;
}

3. 使用

std::copy
算法

std::copy
是STL算法库中的一个通用函数,它能将一个范围内的元素复制到另一个范围。这在需要更精细控制复制过程,或者想复制到现有
vector
的特定位置时非常有用。它要求目标位置有足够的空间。

#include 
#include  // For std::copy
#include 
#include  // For std::back_inserter

int main() {
    std::vector originalData = {1.1, 2.2, 3.3, 4.4};
    std::vector destinationData;

    // 方法一:如果目标vector已经有足够空间,直接复制
    // destinationData.resize(originalData.size());
    // std::copy(originalData.begin(), originalData.end(), destinationData.begin());

    // 方法二:更常见且安全的做法,使用std::back_inserter,它会自动调整目标vector的大小
    std::copy(originalData.begin(), originalData.end(), std::back_inserter(destinationData));

    std::cout << "destinationData using std::copy: ";
    for (double d : destinationData) {
        std::cout << d << " ";
    }
    std::cout << std::endl; // Output: 1.1 2.2 3.3 4.4
    return 0;
}

4. 使用

vector::insert
方法

vector
insert
方法非常强大,它允许你在指定位置插入一个范围的元素。这对于合并
vector
或者在现有
vector
中间插入另一个
vector
的内容很有用。

#include 
#include 

int main() {
    std::vector sourceChars = {'X', 'Y', 'Z'};
    std::vector targetChars = {'A', 'B', 'C'};

    // 将 sourceChars 的内容插入到 targetChars 的末尾
    targetChars.insert(targetChars.end(), sourceChars.begin(), sourceChars.end());

    std::cout << "targetChars after insert: ";
    for (char c : targetChars) {
        std::cout << c << " ";
    }
    std::cout << std::endl; // Output: A B C X Y Z

    // 也可以插入到指定位置
    std::vector middleChars = {'1', '2'};
    targetChars.insert(targetChars.begin() + 3, middleChars.begin(), middleChars.end()); // 插入到 'X' 之前

    std::cout << "targetChars after second insert: ";
    for (char c : targetChars) {
        std::cout << c << " ";
    }
    std::cout << std::endl; // Output: A B C 1 2 X Y Z
    return 0;
}

C++ vector复制性能考量:哪种方法最快?

关于

vector
复制的性能,这其实是一个值得深入探讨的话题,因为它并非一概而论。在我看来,"最快"这个词本身就需要语境。

首先,对于简单的基本类型(如

int
,
double
)或者内存布局紧凑的POD类型,
std::copy
和赋值运算符在底层通常会被编译器优化到极致,很多时候甚至会内联(inlining)并使用像
memcpy
这样的高效内存复制函数。这意味着它们的性能表现会非常接近,甚至可以说几乎没有可感知的差异。如果
vector
预先分配了足够的内存,
std::copy
可能会略微快一点,因为它避免了额外的内存分配和释放操作(如果目标
vector
需要扩容的话)。

然而,当

vector
中存储的是复杂对象(例如
std::string
、自定义类对象)时,情况就有所不同了。这时候的复制不仅仅是内存的简单拷贝,还涉及到每个元素的构造函数和赋值运算符调用。

  • 赋值运算符 (
    =
    ) 和拷贝构造函数:
    它们会确保对每个元素进行正确的深拷贝(如果元素类型有自定义的拷贝构造/赋值行为)。这通常是最安全、最符合预期的行为,但如果元素拷贝开销很大,性能可能会受到影响。它们在内部处理了目标
    vector
    的内存管理(分配、释放、扩容)。
  • std::copy
    配合
    std::back_inserter
    这种组合在功能上与拷贝构造函数类似,它也会对每个元素调用拷贝构造函数。
    std::back_inserter
    会确保目标
    vector
    有足够的空间,如果不够,会触发
    vector
    的动态扩容机制。频繁的扩容可能导致性能下降,因为它涉及内存的重新分配和旧元素的移动。
  • std::copy
    到预分配空间的
    vector
    如果你已经知道源
    vector
    的大小,并预先使用
    targetVec.resize(sourceVec.size())
    targetVec.reserve(sourceVec.size())
    为目标
    vector
    分配了空间,那么
    std::copy
    直接将元素复制到目标
    vector
    的现有内存中,可以避免动态扩容的开销,这通常会非常高效。

一个值得注意的优化点:

std::move
std::swap

如果你在复制之后不再需要源

vector
的内容,那么考虑使用移动语义(
std::move
)会比复制更高效。
std::vector
的移动构造函数和移动赋值运算符通常只是交换了内部的指针和大小信息,而不需要复制实际的元素数据。

// 移动赋值,sourceVec 的内容被“偷走”,sourceVec 变为空或处于有效但未指定状态
std::vector sourceVec = {1, 2, 3};
std::vector destVec;
destVec = std::move(sourceVec); // destVec: {1, 2, 3}, sourceVec 可能为空

// 移动构造
std::vector originalStrings = {"hello", "world"};
std::vector movedStrings(std::move(originalStrings)); // originalStrings 可能为空

此外,如果你只是想交换两个

vector
的内容,
std::swap
是最高效的方式,它通常只交换内部指针,是一个常数时间操作,远快于任何形式的元素复制。

总结一下,对于性能敏感的场景:

  1. 如果源
    vector
    不再需要:
    优先考虑
    std::move
  2. 如果目标
    vector
    可以预先分配空间:
    std::copy
    到预分配的内存通常是最快的。
  3. 对于小
    vector
    或基本类型:
    赋值运算符、拷贝构造函数和
    std::copy
    (配合
    back_inserter
    或预分配)性能差异不大。
  4. 对于包含复杂对象的
    vector
    性能瓶颈往往在于元素的拷贝构造/赋值开销,而不是
    vector
    本身的机制。

如何实现C++ vector的部分内容复制?

在实际开发中,我们经常需要从一个

vector
中提取一部分内容,或者将一个
vector
的部分内容复制到另一个
vector
中。这方面,
std::copy
算法和
vector::insert
方法提供了非常灵活的解决方案。

1. 使用

std::copy
复制指定范围

Amazon Nova
Amazon Nova

亚马逊云科技(AWS)推出的一系列生成式AI基础模型

下载

std::copy
的强大之处在于它接受一对迭代器来定义源范围,以及一个输出迭代器来指定目标起始位置。这使得复制部分内容变得非常简单。

#include 
#include 
#include 
#include 

int main() {
    std::vector original = {10, 20, 30, 40, 50, 60, 70};
    std::vector partialCopy;

    // 复制从第二个元素(索引1)开始,到第四个元素(索引3)结束(不包含)的内容
    // 即复制 20, 30, 40
    std::copy(original.begin() + 1, original.begin() + 4, std::back_inserter(partialCopy));

    std::cout << "Partial copy (20, 30, 40): ";
    for (int x : partialCopy) {
        std::cout << x << " ";
    }
    std::cout << std::endl; // Output: 20 30 40

    // 复制最后N个元素
    std::vector lastThree;
    if (original.size() >= 3) {
        std::copy(original.end() - 3, original.end(), std::back_inserter(lastThree));
    }
    std::cout << "Last three elements: ";
    for (int x : lastThree) {
        std::cout << x << " ";
    }
    std::cout << std::endl; // Output: 50 60 70
    return 0;
}

这里,

original.begin() + 1
指向第二个元素,
original.begin() + 4
指向第五个元素(但不包含)。这种半开区间的表示方式在C++迭代器中非常常见。

2. 使用

vector
的范围构造函数

如果你想用源

vector
的某一部分内容来初始化一个新的
vector
,那么范围构造函数是一个非常简洁且高效的选择。

#include 
#include 

int main() {
    std::vector fullList = {"alpha", "beta", "gamma", "delta", "epsilon"};

    // 创建一个新 vector,包含 fullList 的第二个到第四个元素(不含)
    // 即 "beta", "gamma", "delta"
    std::vector subList(fullList.begin() + 1, fullList.begin() + 4);

    std::cout << "Sub-list constructed: ";
    for (const auto& s : subList) {
        std::cout << s << " ";
    }
    std::cout << std::endl; // Output: beta gamma delta
    return 0;
}

3. 使用

vector::insert
插入指定范围

vector::insert
方法除了可以插入单个元素,也可以接受一对迭代器来插入一个范围的元素到目标
vector
的指定位置。这对于合并部分内容到现有
vector
中非常有用。

#include 
#include 

int main() {
    std::vector mainData = {'A', 'B', 'C', 'G', 'H'};
    std::vector auxiliaryData = {'X', 'Y', 'Z', 'M', 'N'};

    // 将 auxiliaryData 的中间部分(Y, Z)插入到 mainData 的 'C' 和 'G' 之间
    mainData.insert(mainData.begin() + 3, // 插入到索引3的位置
                    auxiliaryData.begin() + 1, // 源范围起始 (Y)
                    auxiliaryData.begin() + 3); // 源范围结束 (不含 M)

    std::cout << "Main data after partial insert: ";
    for (char c : mainData) {
        std::cout << c << " ";
    }
    std::cout << std::endl; // Output: A B C Y Z G H
    return 0;
}

这些方法提供了足够的灵活性来处理各种部分复制的需求。关键在于理解迭代器的工作方式,以及如何精确地定义你想要复制的范围。

C++ vector复制时需要注意的深拷贝与浅拷贝陷阱

在C++中谈论

vector
的复制,特别是当
vector
存储的是对象而非基本类型时,深拷贝(Deep Copy)和浅拷贝(Shallow Copy)的概念就变得尤为重要。这常常是我在代码审查时发现问题的一个重灾区。

std::vector
本身的设计是安全的,它默认会执行元素级的深拷贝。这意味着当你复制一个
std::vector
时,它会为新的
vector
分配独立的内存,并把所有
int
值复制过去。当你复制一个
std::vector
时,它也会为新的
vector
分配内存,并调用每个
std::string
的拷贝构造函数,确保每个
std::string
对象内部管理的字符数据也被独立复制。

然而,"陷阱"往往出现在

vector
存储的是指针(无论是裸指针还是智能指针)时。

1. 裸指针的浅拷贝问题

如果你的

vector
存储的是裸指针,例如
std::vector
,那么
vector
的默认拷贝行为仅仅是复制这些指针的。这意味着两个
vector
会拥有指向同一块内存区域的指针。这就是典型的“浅拷贝”问题。

#include 
#include 
#include  // For smart pointers, though not used in this raw pointer example

class MyData {
public:
    int value;
    MyData(int v) : value(v) {}
    ~MyData() { std::cout << "MyData " << value << " destroyed." << std::endl; }
};

int main() {
    std::vector sourcePtrs;
    sourcePtrs.push_back(new MyData(10));
    sourcePtrs.push_back(new MyData(20));

    std::vector copiedPtrs = sourcePtrs; // 浅拷贝:只复制了指针的值

    std::cout << "Original value: " << copiedPtrs[0]->value << std::endl; // Output: 10
    copiedPtrs[0]->value = 100; // 通过 copiedPtrs 修改了数据

    std::cout << "Value via sourcePtrs: " << sourcePtrs[0]->value << std::endl; // Output: 100 (被修改了!)

    // 潜在问题1:重复释放内存
    // delete copiedPtrs[0]; // 第一次释放
    // delete sourcePtrs[0]; // 第二次释放,导致双重释放错误!

    // 潜在问题2:内存泄漏
    // 如果不手动 delete,则所有 MyData 对象都泄漏了。
    // 正确的做法是只在一个 vector 管理生命周期,或者使用智能指针。

    // 清理 sourcePtrs 负责的对象
    for (MyData* ptr : sourcePtrs) {
        delete ptr;
    }
    sourcePtrs.clear(); // 清空指针,但对象已释放
    copiedPtrs.clear(); // 此时 copiedPtrs 内部的指针已悬空或指向已释放内存
    return 0;
}

在这个例子中,

copiedPtrs
sourcePtrs
的元素都指向了堆上相同的
MyData
对象。如果你通过
copiedPtrs[0]
修改了对象,
sourcePtrs[0]
也能看到这个修改。更糟糕的是,如果两个
vector
都尝试
delete
这些指针,就会导致双重释放(double free)错误,这是非常危险的。

解决方案:手动实现深拷贝

如果你确实需要

vector
并且希望复制时也复制
MyObject
本身,你需要手动遍历并创建新的对象:

std::vector sourcePtrs;
sourcePtrs.push_back(new MyData(10));
sourcePtrs.push_back(new MyData(20));

std::vector deepCopiedPtrs;
for (MyData* ptr : sourcePtrs) {
    deepCopiedPtrs.push_back(new MyData(*ptr)); // 调用 MyData 的拷贝构造函数
}

// 现在修改 deepCopiedPtrs[0] 不会影响 sourcePtrs[0]
deepCopiedPtrs[0]->value = 100;
std::cout << "Value via sourcePtrs: " << sourcePtrs[0]->value << std::endl; // Output: 10 (未被修改)

// 清理
for (MyData* ptr : sourcePtrs) {
    delete ptr;
}
for (MyData* ptr : deepCopiedPtrs) {
    delete ptr;
}

显然,这种手动管理内存的方式非常容易出错且繁琐。

2. 智能指针的正确使用

为了避免裸指针带来的内存管理复杂性,C++引入了智能指针。当

vector
存储智能指针时,情况会更安全。

  • std::vector>
    unique_ptr
    表示独占所有权。因此,
    std::vector>
    不可复制的。如果你尝试复制它,编译器会报错。这是因为复制
    unique_ptr
    意味着两个
    unique_ptr
    会尝试管理同一个资源,这违反了其独占所有权的语义。如果你想“复制”它,你只能移动它,或者遍历源
    vector
    ,为每个元素创建新的
    unique_ptr
    指向新的`My

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

312

2023.08.02

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1435

2023.10.24

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

225

2024.02.23

php三元运算符用法
php三元运算符用法

本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

85

2025.10.17

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

312

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

522

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

49

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

190

2025.08.29

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

74

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 3.2万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号