c++ vector容器 创建动态数组及拷贝优化

vector包含在c++标准模版库中,能够存放任意类型的动态数组,类似于一个容器,能够增加数据和减少数据

使用方法如下:

#include <iostream>
#include <vector>

struct Vertex{
	int x,y,z;

	Vertex(int a, int b, int c)
	: x(a), y(b),z(c){}
};

std::ostream& operator<<(std::ostream& stream, const Vertex& vertex){
	stream << vertex.x << "," << vertex.y << "," << vertex.z;
	return stream;
}

int main(){
	std::vector<Vertex> vertices;
	Vertex v1(1,2,3);
	Vertex v2(4,5,6);
	vertices.push_back(v1);
	vertices.push_back(v2);

	for(int i = 0; i< vertices.size(); i++){
		std::cout << vertices[i] <<std::endl;
	}

	vertices.erase(vertices.begin() +1);

	for(Vertex& v : vertices){
		std::cout << v << std::endl;
	}

	std::cin.get();
}

1. #include <vector> 声明头文件

2. std::vector<Vertex> vertices; 创建动态数组(数组类型为Vertex)

3. vertices.push_back(v1); 将Vertex类型的变量v1加入数组

4. vertices.erase(vertices.begin() +1); 删除第二个位置的值

当往vector数组添加元素时,会发生多次没必要的拷贝,降低代码效率,如下:

#include <iostream>
#include <vector>
 
struct Vertex{
	int x,y,z;
 
	Vertex(int a, int b, int c)
	: x(a), y(b),z(c){}

	Vertex(const Vertex& vertex)
	:x(vertex.x), y(vertex.y), z(vertex.z){
		std::cout << "copy" << std::endl;
	}
};
 
std::ostream& operator<<(std::ostream& stream, const Vertex& vertex){
	stream << vertex.x << "," << vertex.y << "," << vertex.z;
	return stream;
}
 
int main(){
	std::vector<Vertex> vertices;

	Vertex v1(1,2,3);
	Vertex v2(4,5,6);
	Vertex v3(4,5,6);
	vertices.push_back(v1);
	vertices.push_back(v2);
  	vertices.push_back(v3);

	std::cin.get();
}

当动态数组创建时,因为没有包含元素,所以不占用内存。当需要push元素进数组时,系统会调整数组长度为1,然后拷贝该元素到数组。当再次push第二个元素时,系统会调整数组长度为2,而且会指定一个新的内存地址,然后把两个元素都拷贝过去。这就降低了效率。同理,第三个元素时,拷贝次数到了6次。

$ ./a.out
copy
copy
copy
copy
copy
copy

为了应对该问题,分两步:

1. 先为该数组预留长度,这样只要数组实际长度没达到这个值,就不会发生上述现象。代码如下:

vertices.reserve(3);  
#include <iostream>
#include <vector>
 
struct Vertex{
	int x,y,z;
 
	Vertex(int a, int b, int c)
	: x(a), y(b),z(c){}

	Vertex(const Vertex& vertex)
	:x(vertex.x), y(vertex.y), z(vertex.z){
		std::cout << "copy" << std::endl;
	}
};
 
std::ostream& operator<<(std::ostream& stream, const Vertex& vertex){
	stream << vertex.x << "," << vertex.y << "," << vertex.z;
	return stream;
}
 
int main(){
	std::vector<Vertex> vertices;
    vertices.reserve(3);

	Vertex v1(1,2,3);
	Vertex v2(4,5,6);
	Vertex v3(4,5,6);
	vertices.push_back(v1);
	vertices.push_back(v2);
 	vertices.push_back(v3);


	std::cin.get();
}

运行结果显示,只发生了三次拷贝

$ ./a.out
copy
copy
copy

2. 进一步优化,即不在main函数中创建元素再拷贝到数组,而是直接在预留的内存地址生成,代码如下

vertices.emplace_back(1,2,3);
vertices.emplace_back(4,5,6);
vertices.emplace_back(7,8,9);
#include <iostream>
#include <vector>
 
struct Vertex{
	int x,y,z;
 
	Vertex(int a, int b, int c)
	: x(a), y(b),z(c){}

	Vertex(const Vertex& vertex)
	:x(vertex.x), y(vertex.y), z(vertex.z){
		std::cout << "copy" << std::endl;
	}
};
 
std::ostream& operator<<(std::ostream& stream, const Vertex& vertex){
	stream << vertex.x << "," << vertex.y << "," << vertex.z;
	return stream;
}
 
int main(){
	std::vector<Vertex> vertices;
    vertices.reserve(3);

	// Vertex v1(1,2,3);
	// Vertex v2(4,5,6);
	// Vertex v3(4,5,6);
	// vertices.push_back(v1);
	// vertices.push_back(v2);
 // 	vertices.push_back(v3);
	vertices.emplace_back(1,2,3);
	vertices.emplace_back(4,5,6);
	vertices.emplace_back(7,8,9);

	std::cin.get();
}

运行结果显示一次拷贝也没有发生。

注意在mac上编译时,如果使用xcode工具链的编译工具,会报错

C++中,`std::vector`是一种动态数组容器,用于存储同类型的元素,并支持自动增长功能。关于`vector`的拷贝操作分为浅拷贝和深拷贝两种。 ### 浅拷贝拷贝涉及到复制指向原始数据的数据结构(如指针),即创建一个的对象,将原来的对象的内存地址赋值给对象。这种方式只复制了容器指向的数据的位置,而没有实际移动或复制数据本身。因此,在浅拷贝的情况下,两个`vector`实例之间共享相同的内部数据缓冲区,这可能导致修改其中一个实例会同时影响另一个实例的问题。 ```cpp #include <iostream> #include <vector> int main() { std::vector<int> original = {1, 2, 3}; std::vector<int> shallowCopy(&original, &original[original.size()]); // 修改原vector的第二个元素 original = 4; // 打印浅拷贝的结果 for (const auto& elem : shallowCopy) { std::cout << elem << " "; } // 输出结果应为 1 4 3 ,说明浅拷贝后的vector也跟着改变了 } ``` ### 深拷贝拷贝则涉及到复制容器内的所有数据成员。这意味着创建一个的独立内存区域并填充相同的内容,而不是简单地引用现有的内存位置。在这种情况下,每个`vector`实例都拥有自己的数据副本,所以对其中一个实例的修改不会影响到其他实例。 ```cpp #include <iostream> #include <vector> int main() { std::vector<int> original = {1, 2, 3}; std::vector<int> deepCopy(original); // 使用构造函数或copy构造函数进行深拷贝 // 修改原vector的第一个元素 original = -1; // 打印深拷贝的结果 for (const auto& elem : deepCopy) { std::cout << elem << " "; } // 输出结果应为 1 2 3 ,说明深拷贝后的vector保持不变 } ``` ### 相关问题: 1. **如何手动实现`vector`的深拷贝?** 可以通过构造函数的方式或者使用`std::vector::operator=(const vector&)`进行深拷贝,但是需要特别注意的是,使用这种拷贝赋值符可能会引发效率低下或资源泄露问题,因为它们通常默认实现为浅拷贝,除非在内部进行了特殊的优化。 2. **何时应该使用深拷贝而非浅拷贝?** 当处理不可变的数据或希望确保各个实例之间的数据独立时,应使用深拷贝。例如,当你构建的对象包含昂贵的计算生成的资源时,避免浅拷贝可以节省内存和计算资源。 3. **深拷贝和浅拷贝在性能上有何差异?** 深拷贝通常比浅拷贝更耗时和消耗更多内存,因为它涉及复制整个数据集合。然而,从维护数据一致性以及防止副作用的角度考虑,其额外的成本可能是值得的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值