- 动态数组,特别是讨论标准向量类
- 要习惯CPP的标准库(标准模版库)
- 标准模版库包含了各种容器、迭代器、算法、仿函数
- 容器的数据类型由程序员自己决定
- cpp提供了一个Vector的类,在std命名空间中,可以调整大小,也可以不指定初始大小
- 本系列会重写C++中的数据结构,优化后比标准模版库中的快很多
std::vector 的实际工作方式:
当超出实际的分配大小时。当创建一个向量,可能会先分配10个元素大小的空间,当超出这个大小时,会在内存中创建一个比原来更大的数组,并把所有内容复制过去,然后删除旧数组。这样就有了一个更大存储空间的新数组
46动态数组#
struct Test
{
};
struct Vertex
{
float x, y, z;
/*virtual*/ void test()
{
}
};
//main()中
Vertex v = { 1,2,3 };
聚合初始化(Aggregate Initialization),Vertex 结构体是一个聚合类型(Aggregate Type)。在 C++ 中,如果一个类或结构体满足以下条件:
- 没有显式定义的构造函数。
- 成员变量是公有的(public)。
- 没有基类(没有继承)。
- 没有虚函数。
那么你可以使用大括号 {} 直接按顺序为成员变量赋值。
vector的基本使用#
#include <iostream>
#include <string>
#include <vector>
struct Test
{
};
struct Vertex
{
float x, y, z;
//有了其他的构造函数,如果需要用到无参构造函数,
//就必须手动写一个
Vertex()
{
}
//因为有构造函数了,所以Vertex 结构体不是一个聚合类型(
// 有构造函数),所以要使用显示构造函数
// 使 Vertex v = { 1,2,3 }; 编译通过
Vertex(float x, float y, float z)
{
this->x = x;
this->y = y;
this->z = z;
}
//参数必须是&,原因如下:
//1. 当你尝试通过 Vertex a = b; 调用复制构造函数时,你需要将 b 传递给参数 other。
//2. 在 C++ 中,按值传递(Pass by Value)参数本身就会触发一次复制。
//3. 为了复制 b 到 other,编译器又需要调用复制构造函数。[死循环了]
//因为main中使用 vector.push({1,2,3}) 需要将临时对象拷贝到vector中,所以这里的参数
//必须是const
Vertex(const Vertex& vertex)
{
std::cout << "copied constructor handled" << std::endl;
this->x = vertex.x;
this->y = vertex.y;
this->z = vertex.z;
}
/*virtual*/ void test()
{
}
~Vertex()
{
std::cout << "destructor handled" << std::endl;
}
};
std::ostream& operator<<(std::ostream& stream, const Vertex& vertex)
{
stream << vertex.x << "," << vertex.y << "," << vertex.z;
return stream;
}
int main()
{
Vertex vertices1[5];
Vertex* vertices2 = new Vertex[5];
std::vector<int> myarray;
//存储Vertex对象,则动态数组的内存是连续的,
//其中的Vertext对象会按行排列
//问题是:实际要调整向量大小时得复制所有(类)数据,但内存连续性
// 带来的读取速度提升通常远超扩容时的开销
std::vector<Vertex> vertices;
//存储Vertext指针,实际要调整向量大小是只是复制指针地址(一个数字)
//,即实际数据的内存地址
std::vector<Vertex*> vertices4;
std::cout << "---1---" << std::endl;
Vertex v = { 1,2,3 };
//这里演示vertices的使用
std::cout << "---2---" << std::endl;
vertices.push_back({ 1,2,3 });
std::cout << "---3---" << std::endl;
vertices.push_back({ 4,5,6 });
std::cout << "---4---" << std::endl;
for (int i = 0; i < vertices.size(); i++)
{
//c++对[]进行了重载
std::cout << vertices[i] << std::endl;
}
std::cout << "---5---" << std::endl;
//这里会把每个Vertex复制到v
for (Vertex v : vertices)
std::cout << v << std::endl;
std::cout << "---6---" << std::endl;
//避免复制
for (Vertex& v : vertices)
std::cout << v << std::endl;
//clear() 会移除容器中的所有元素,但通常不一定会立即释放底层内存(容量不变),它只是销毁现有的对象。
vertices.clear();
std::cin.get();
}
解释一下vertices.push_back({1, 2, 3});#
当你执行 vertices.push_back({1, 2, 3}); 时,逻辑确实是:在 vector 内部的内存中,通过调用复制构造函数来构造一个属于 vector 自己的对象。