如何解决std :: vector保留的成本比预期的高
因此,为了效率起见,我需要手动处理std :: vector分配的内存。而且我注意到我的程序比预期的要慢,所以我在代码库的各处添加了这个惯用法:
const uint new_edges_capacity = mesh.edges.size() + 6;
if(new_edges_capacity > mesh.edges.capacity())
mesh.edges.reserve(new_edges_capacity * 2);
最初我只是在做:
const uint new_edges_capacity = mesh.edges.size() + 6;
mesh.edges.reserve(new_edges_capacity * 2);
好吧,第一个摘要比第二个要快几个数量级。
我不明白,官方文件似乎暗示储备金应该已经在进行与我相同的检查。但是,perf
绝对将std :: reserve标记为我的代码中最昂贵的操作,并且确实进行了修改,表明不调用reserve并依靠它来检查分配是否更快。
我正在使用此模式的函数示例:
template<typename V>
void HMesh<V>::SplitFace(uint face_id,HMesh<V>& mesh)
{
mesh.vertex_data.push_back({});
mesh.verts.push_back({&mesh});
HMesh<V>::MVert& c = mesh.verts.back();
const uint new_edges_capacity = mesh.edges.size() + 6;
if(new_edges_capacity > mesh.edges.capacity())
mesh.edges.reserve(new_edges_capacity * 2);
mesh.edges.push_back({&mesh});
HMesh<V>::MEdge& n00 = mesh.edges.back();
mesh.edges.push_back({&mesh});
HMesh<V>::MEdge& n01 = mesh.edges.back();
mesh.edges.push_back({&mesh});
HMesh<V>::MEdge& n10 = mesh.edges.back();
mesh.edges.push_back({&mesh});
HMesh<V>::MEdge& n11 = mesh.edges.back();
mesh.edges.push_back({&mesh});
HMesh<V>::MEdge& n20 = mesh.edges.back();
mesh.edges.push_back({&mesh});
HMesh<V>::MEdge& n21 = mesh.edges.back();
const uint new_faces_capacity = mesh.faces.size() + 2;
if(new_faces_capacity > mesh.faces.capacity())
mesh.faces.reserve(new_faces_capacity * 2);
mesh.faces.push_back({&mesh});
HMesh<V>::MFace& f1 = mesh.faces.back();
mesh.faces.push_back({&mesh});
HMesh<V>::MFace& f2 = mesh.faces.back();
auto& face = mesh.faces[face_id];
HMesh<V>::MFace& f0 = face;
HMesh<V>::MEdge& e0 = face.EdgeD();
HMesh<V>::MEdge& e1 = face.EdgeD().NextD();
HMesh<V>::MEdge& e2 = face.EdgeD().PrevD();
HMesh<V>::MVert& v0 = e0.VertD();
HMesh<V>::MVert& v1 = e1.VertD();
HMesh<V>::MVert& v2 = e2.VertD();
ConnectFace(f0,n00,e0,n10);
ConnectFace(f1,n11,e1,n21);
ConnectFace(f2,n20,e2,n01);
Pair(n00,n01);
Pair(n10,n11);
Pair(n20,n21);
AttachVertices(n00,c,v0);
AttachVertices(n11,v1);
AttachVertices(n20,v2);
c.Data({
(v0.Data().position + v1.Data().position + v2.Data().position) / 3.0,(v0.Data().uv + v1.Data().uv + v2.Data().uv) / 3.0,{0,1}
});
}
解决方法
您没有重新实现reserve
,而是在容量耗尽时重新实现了调整大小操作。问题是,如果每次插入项目都这样做,那么每次都会调整大小,进行每次操作O(n)
(因为它必须从原始后备存储中移走所有项目到更大的新存储中)。如果您每次都是从空白的vector
开始运行,则会看到以下模式:
Size Capacity Reallocation needed?
1 14 Yes
2 16 Yes (16 > 14)
3 18 Yes (18 > 16)
4 20 Yes (20 > 18)
... reallocations continue forever ...
,并且这些大小调整中的每一个都会导致新的分配,所有现有元素的移动以及旧分配的清理(使用从源移出对象触发的析构函数)。您尚未保存任何内容,因为您每次都会强制进行新的分配,从而避免了不必要的分配(这显然是无济于事的)。
在使用if
测试的情况下,由于如果测试失败,则针对reserve
一半的值进行测试,因此重新分配的频率要低得多:
Size Capacity Reallocation needed?
1 14 Yes
2 14 No (2 + 6 <= 14)
3 14 No (3 + 6 <= 14)
4 14 No (4 + 6 <= 14)
5 14 No (5 + 6 <= 14)
6 14 No (6 + 6 <= 14)
7 14 No (7 + 6 <= 14)
8 14 No (8 + 6 <= 14)
9 30 Yes (9 + 6 > 14)
... very rare reallocations ...
如您所见,您的测试意味着远的调整大小活动较少。
如果您只是想猜测需要多少空间,请不要;让vector
根据需要自动调整大小(每次 都加倍,可能会在默认的摊销增长时间表上为您节省一点时间,但同时也会浪费大量内存)。 reserve
用于当您知道需要多少空间时;一遍又一遍地使用它很昂贵。
您完全不需要保留 。只需使用索引即可。
template<typename V>
void HMesh<V>::SplitFace(uint face_id,HMesh<V>& mesh)
{
mesh.vertex_data.push_back({});
mesh.verts.push_back({&mesh});
HMesh<V>::MVert& c = mesh.verts.back();
const uint n = mesh.edges.size();
mesh.edges.push_back({&mesh});
mesh.edges.push_back({&mesh});
mesh.edges.push_back({&mesh});
mesh.edges.push_back({&mesh});
mesh.edges.push_back({&mesh});
mesh.edges.push_back({&mesh});
auto & n00 = mesh.edges[n + 0];
auto & n01 = mesh.edges[n + 1];
auto & n10 = mesh.edges[n + 2];
auto & n11 = mesh.edges[n + 3];
auto & n20 = mesh.edges[n + 4];
auto & n21 = mesh.edges[n + 5];
const uint f = mesh.faces.size();
mesh.faces.push_back({&mesh});
mesh.faces.push_back({&mesh});
auto& f0 = mesh.faces[face_id];
auto& f1 = mesh.faces[f + 0];
auto& f2 = mesh.faces[f + 1];
auto& e0 = f0.EdgeD();
auto& e1 = f0.EdgeD().NextD();
auto& e2 = f0.EdgeD().PrevD();
auto& v0 = e0.VertD();
auto& v1 = e1.VertD();
auto& v2 = e2.VertD();
ConnectFace(f0,n00,e0,n10);
ConnectFace(f1,n11,e1,n21);
ConnectFace(f2,n20,e2,n01);
Pair(n00,n01);
Pair(n10,n11);
Pair(n20,n21);
AttachVertices(n00,c,v0);
AttachVertices(n11,v1);
AttachVertices(n20,v2);
c.Data({
(v0.Data().position + v1.Data().position + v2.Data().position) / 3.0,(v0.Data().uv + v1.Data().uv + v2.Data().uv) / 3.0,{0,1}
});
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。