为此任务分配内存的最快方法

Fastest way to allocate memory for this task

提问人:BENG 提问时间:8/29/2023 更新时间:8/29/2023 访问量:110

问:

我正在开发 C++/OpenGL 3D 网格建模软件。基本上是一个非常原始的搅拌机。

A 包含顶点缓存(下面的类),其顶点数据存储在单个块中以发送到 glBufferData。这就是下面的向量。然后,与每个顶点相关联的是边索引和面索引的动态数组,这些索引引用包含该顶点的边和面的 ID。MeshEditCache<Vertex>vertices

template<typename T>
class EditCache {
private:
    std::vector<T> vertices;
    std::vector<std::vector<int>> edge_indices;
    std::vector<std::vector<int>> face_indices;

public:
int addVertex(T vertex) {
        vertices.push_back(vertex);
        edge_indices.push_back(std::vector<int>());
        face_indices.push_back(std::vector<int>());
        return vertices.size() - 1;
    }

void pairEdgeIndex(int vertex_index, int edge_index) {
        edge_indices[point_index].push_back(edge_index);
    }

void pairFaceIndex(int vertex_index, int face_index) {
        face_indices[point_index].push_back(face_index);
    }

...

};

当在现有顶点的类中创建新的边或面时,新边/面的 ID 将推送回与边/面中的每个顶点关联的数组。当创建一个新顶点时,它被推回数组,并在新顶点的位置推回两个新的空向量,以保存包含新顶点的边和面列表。Meshedge_indicesface_indicesvertices

数据结构大致如下所示(而不是它在内存中的存储方式)。

- vertex_0 | { edge_0, ..., edge_n } | { face_0, ..., face_m }
- vertex_1 | { edge_0, ..., edge_n } | { face_0, ..., face_m }
- vertex_2 | { edge_0, ..., edge_n } | { face_0, ..., face_m }
- ...

其中,每个边或面列表的长度是可变的。在内存中,每列(顶点、边索引和面索引)是三个独立的数组。

在创建新的四边形、面或具有许多新顶点的更大结构时,我必须多次执行以创建新顶点,并将每个顶点与其每个新边和面配对。而且一个一个地分配内存真的很慢。我认为我有优化空间的问题是:std::vector.push_back()

1.) 边缘和面 ID 的数组不必是连续的,它们可以是链表。

2.) 我会知道在任务开始时我将添加多少点。

因此,在理想情况下,我会分配一个我需要的大小块,然后将每个数据点一个接一个地附加到新空间中的每个链表中。如何完成此任务?当然,我不喜欢公开和操作,也不喜欢将原始指针暴露给自由空间。有没有办法用 or 来做到这一点?如何以安全的方式分配内存?newdeletestd::unique_ptrstd::shared_ptr

C++ 指针 向量 链接列表 动态内存分配

评论

8赞 Sam Varshavchik 8/29/2023
你有什么证据证明“一个接一个地分配内存[而且]真的很慢”? C++ 标准要求比这智能得多。std::vector::push_backpush_back
8赞 paddy 8/29/2023
使用 时,如果您已经知道要添加多少个元素,那么最好提前调用以分配足够的内存。push_backreserve
3赞 Retired Ninja 8/29/2023
std::vector 和 std::string 重新分配策略初始化 C++ 向量的大小值得一读,如果您不确定向量在已满时如何分配空间。或 没有其他内存泄漏问题。如果向量被销毁,则释放内存。resizereserve
3赞 Dave S 8/29/2023
>“是 24 push_back调用速度极慢”,---在内存中对集合执行的大多数任何操作中少于 100 次太快而无法注意到。即使是 1,000+ 通常也太快了,除非你用它做一些 O(N^2) 的事情,比如对未排序列表的线性搜索。即便如此,如果你只做一次,你可能不在乎——1/100 秒与 1/2 秒对很多事情来说并不重要
3赞 drescherjm 8/29/2023
您是否正在测试优化/发布模式?我问这个问题是因为 msvc 在调试模式下为堆/内存损坏测试增加了大量开销,这可能会导致速度大幅减慢。对于相同的代码和数据,我看到调试模式的执行时间是发布模式的 100 倍。

答:

2赞 463035818_is_not_an_ai 8/29/2023 #1

因此,在理想情况下,我会分配一个我需要的大小块,然后将每个数据点一个接一个地附加到新空间中的每个链表中。如何完成此任务?

当您知道需要多少空间时,可以预先为向量保留空间:

 std::vector<int> x;
 x.reserve(100000);

 // then later
 x.push_back(42);  // no allocation happens here

坦率地说,我认为你的其他问题只是因为预期事情比实际情况更复杂而引发的。您不需要手动,也不需要智能指针,矢量可以做到这一点(而且它不是不安全的)。newdelete