std :: vector保留的成本比预期的高

如何解决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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-