问题分析
让我们先看一个简单的三维向量类Vector3D的实现和使用std::vector<Vector3D>的示例:
代码示例
class Vector3D
{
private:
int m_X, m_Y, m_Z;
public:
Vector3D(int x, int y, int z)
: m_X(x), m_Y(y), m_Z(z)
{
std::cout << "Vector3D(" << m_X << ',' << m_X << ',' << m_X << ") is created" << std::endl;
}
Vector3D(const Vector3D& vec)
: m_X(vec.m_X), m_Y(vec.m_Y), m_Z(vec.m_Z)
{
std::cout << "Copied!!" << std::endl;
}
friend std::ostream& operator<<(std::ostream& stream, const Vector3D& vec);
};
std::ostream& operator<<(std::ostream& stream, const Vector3D& vec)
{
stream << vec.m_X << ',' << vec.m_Y << ',' << vec.m_Z;
return stream;
}
int main()
{
std::vector<Vector3D> v;
v.push_back(Vector3D(1, 2, 3));
v.push_back(Vector3D(2, 3, 4));
v.push_back(Vector3D(3, 4, 5));
for (const Vector3D& it : v)
{
std::cout << it << std::endl;
}
}
运行结果
Vector3D(1,1,1) is created
Copied!!
Vector3D(2,2,2) is created
Copied!!
Copied!!
Vector3D(3,3,3) is created
Copied!!
Copied!!
Copied!!
1,2,3
2,3,4
3,4,5
从输出可以看出存在两个主要问题:
- 临时对象拷贝:每次调用
push_back时,都会先构造一个临时Vector3D对象,然后再将其拷贝到vector中 - 容量扩展拷贝:当vector容量不足时,会分配新的内存空间并将原有元素全部拷贝过去,导致额外的拷贝操作
解决方法
针对上述两个问题,我们在使用的过程中需要注意使用方式:
1. 预先分配足够容量
使用reserve()方法预先分配足够的空间,避免动态扩容带来的拷贝开销:
std::vector<Vector3D> v;
v.reserve(3); // 预先分配3个元素的空间
2. 使用emplace_back替代push_back
emplace_back直接在vector的内存空间中构造对象,避免了临时对象的创建和拷贝:
v.emplace_back(1, 2, 3); // 直接在vector中构造对象
优化后的代码示例
class Vector3D
{
private:
int m_X, m_Y, m_Z;
public:
Vector3D(int x, int y, int z)
: m_X(x), m_Y(y), m_Z(z)
{
std::cout << "Vector3D(" << m_X << ',' << m_X << ',' << m_X << ") is created" << std::endl;
}
Vector3D(const Vector3D& vec)
: m_X(vec.m_X), m_Y(vec.m_Y), m_Z(vec.m_Z)
{
std::cout << "Copied!!" << std::endl;
}
friend std::ostream& operator<<(std::ostream& stream, const Vector3D& vec);
};
std::ostream& operator<<(std::ostream& stream, const Vector3D& vec)
{
stream << vec.m_X << ',' << vec.m_Y << ',' << vec.m_Z;
return stream;
}
int main()
{
std::vector<Vector3D> v;
v.reserve(3);
v.emplace_back(1, 2, 3);
v.emplace_back(2, 3, 4);
v.emplace_back(3, 4, 5);
for (const Vector3D& it : v)
{
std::cout << it << std::endl;
}
}
运行结果
Vector3D(1,1,1) is created
Vector3D(2,2,2) is created
Vector3D(3,3,3) is created
1,2,3
2,3,4
3,4,5
可以看到,优化后的代码完全消除了不必要的拷贝操作,效率显著提高。
总结
通过合理使用reserve和emplace_back,我们可以显著减少std::vector使用过程中的不必要拷贝,提高程序性能。这种优化对于包含复杂对象的vector尤为重要。记住:预先规划好容量,尽量直接在容器中构造对象,是高效使用std::vector的关键。
2万+

被折叠的 条评论
为什么被折叠?



