文章是参考了Cherno大神的C++视频做的总结
有这么一段c++代码,如下:
样例代码
#include<iostream>
#include<vector>
struct Vertex{
float x,y,z;
Vertex(float x,float y,float z)
:x(x),y(y),z(z)
{
}
Vertex(const Vertex& Vertex)
:x(Vertex.x),y(Vertex.y),z(Vertex.z)
{
std::cout<<"Vertex被Copy了一次"<<std::endl;
}
};
int main(){
std::vector<Vertex> Vertices;
Vertices.push_back({1,2,3});
Vertices.push_back({4,5,6});
Vertices.push_back({7,8,9});
return 0;
}
其中这一段是拷贝构造函数,不懂的可以参考文章c++拷贝构造函数
Vertex(const Vertex& Vertex)
:x(Vertex.x),y(Vertex.y),z(Vertex.z)
{
std::cout<<"Vertex被Copy了一次"<<std::endl;
}
当运行上面代码的时候,会得到以下输出
可以发现"Vertex被Copy了一次"被打印了六次。这是为什么?
这是因为每次push_back
会构造一个临时Vertex
对象,随后调用拷贝构造函数将其复制到vector中。
拷贝次数计算
- 第一次
push_back
:- 构造临时对象(无输出)。
- 拷贝到vector(1次拷贝)。
- 第二次
push_back
:- 构造临时对象(无输出)。
- 扩容至2,拷贝旧元素(1次)。
- 拷贝临时对象(1次)。
- 总计2次。
- 第三次
push_back
:- 构造临时对象(无输出)。
- 扩容至4,拷贝前两个元素(2次)。
- 拷贝临时对象(1次)。
- 总计3次。
- 总拷贝次数:1 + 2 + 3 = 6次,输出6次"Vertex被Copy了一次"。
这段代码在向std::vector
添加元素时存在不必要的拷贝操作,导致性能下降。
接下来讲解如何优化。
优化
优化建议
使用emplace_back
替代push_back
:直接在vector内存中构造对象,避免临时对象拷贝。
Vertices.emplace_back(1, 2, 3); // 无需拷贝,直接构造
预分配内存reserve()
:避免动态扩容时的多次拷贝。
std::vector<Vertex> Vertices;
Vertices.reserve(3); // 预分配足够空间
添加移动构造函数(可选):若元素需频繁转移,定义移动语义提升效率。
Vertex(Vertex&&) = default; // 显式默认移动构造函数
以下是优化后的代码:
#include<iostream>
#include<vector>
struct Vertex{
float x,y,z;
Vertex(float x,float y,float z)
:x(x),y(y),z(z)
{}
Vertex(const Vertex& other)
:x(other.x),y(other.y),z(other.z)
{
std::cout << "Vertex被Copy了一次" << std::endl;
}
};
int main(){
std::vector<Vertex> Vertices;
Vertices.reserve(3); // 预分配内存,避免扩容
Vertices.emplace_back(1, 2, 3); // 直接构造,无拷贝
Vertices.emplace_back(4, 5, 6);
Vertices.emplace_back(7, 8, 9);
return 0;
}
可以看到就没有打印"Vertex被Copy了一次"了,说明没有拷贝构造函数的调用。
优化讲解
push_back和emplace_back有什么区别?
C++中push_back和emplace_back有什么区别?
vertices.reserve(3);和std::vector<Vertex> vertices(3);有什么区别?
vertices.reserve(3);
:该语句是针对已经存在的std::vector
对象vertices
进行操作。它的主要功能是为vector
预先分配足够存储3个Vertex
类型元素的内存空间,但并不会创建实际的元素。也就是说,此时vector
的大小(size()
)仍然为0,只是容量(capacity()
)变为了3。std::vector<Vertex> vertices(3);
:这是在声明并初始化std::vector
对象vertices
。它会直接创建一个包含3个Vertex
类型元素的vector
,每个元素都会调用Vertex
类的默认构造函数进行初始化。此时vector
的大小(size()
)和容量(capacity()
)都为3。