Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用vector时的内存管理_C++_Vector_Memory Management - Fatal编程技术网

C++ 使用vector时的内存管理

C++ 使用vector时的内存管理,c++,vector,memory-management,C++,Vector,Memory Management,我正在制作一个游戏引擎,需要为游戏中的所有组件和实体使用std::vector容器 在脚本中,用户可能需要持有一个指向实体或组件的指针,也许是为了持续检查某种状态。如果向指针指向的向量添加了某些内容,并且超出了容量,我的理解是,向量将分配新内存,并且指向向量中任何元素的每个指针都将无效 考虑到这个问题,我有几个可能的解决方案。每次推回矢量后,检查当前容量变量是否超过矢量的实际容量是否可行?如果是这样,获取并覆盖指向新指针的旧指针?这能保证在执行push_-back时捕获所有使指针无效的情况吗 我

我正在制作一个游戏引擎,需要为游戏中的所有组件和实体使用std::vector容器

在脚本中,用户可能需要持有一个指向实体或组件的指针,也许是为了持续检查某种状态。如果向指针指向的向量添加了某些内容,并且超出了容量,我的理解是,向量将分配新内存,并且指向向量中任何元素的每个指针都将无效

考虑到这个问题,我有几个可能的解决方案。每次推回矢量后,检查当前容量变量是否超过矢量的实际容量是否可行?如果是这样,获取并覆盖指向新指针的旧指针?这能保证在执行push_-back时捕获所有使指针无效的情况吗

我发现的另一个解决方案是将索引保存到元素并以这种方式访问它,但我怀疑,当您需要每隔1/60秒连续检查该元素的状态时,这对性能是有害的

我知道其他容器没有这个问题,但我真的想让它与向量一起工作。另外,可能值得注意的是,我事先不知道将有多少实体/组件


非常感谢您的任何意见

当每秒仅访问std::vector元素60次时,您不必担心它的性能。顺便说一下,在版本编译模式下,std::vector::operator[]正在转换为单个lea操作码。但在调试模式下,它会通过一些运行时范围检查进行修饰。

当每秒仅访问std::vector元素60次时,您不必担心它的性能。顺便说一下,在版本编译模式下,std::vector::operator[]正在转换为单个lea操作码。在调试模式下,它会被一些运行时范围检查修饰。

如果用户要存储指向对象的指针,为什么还要将它们包含在向量中

我觉得在向量中存储指向对象的指针不是一个好主意。我的意思是创建指向向量元素的指针,即my_ptr=&my_vec[n];容器的要点是以容器支持的正常方式引用内容,而不是创建指向容器元素的外部指针

要回答您关于是否可以检测分配的问题,是的,您可以,但是通过指向元素的指针引用向量的内容可能仍然是个坏主意

如果您对向量的最大大小可能增长到什么程度有所了解,那么也可以在创建向量时在向量中保留空间。那么它永远不会调整大小

编辑:

在阅读了其他的回答,并思考了你的问题后,另一个想法出现了。如果向量是指向对象的指针向量,并且将指向对象的指针传递给客户端,则调整向量大小不会使向量所包含的指针无效。问题变成了跟踪拥有它的对象的生命周期,这就是为什么使用shared_ptr会很有用

例如:

vector<shared_ptr> my_vec;
my_vec.push_back(stuff);
向量调整大小时不会出现问题。向量的内容将被保留,而my_vec[3]上的内容仍将保留。my_vec[3]指向的对象仍将位于同一地址,my_vec[3]仍将包含该地址。在my_vec[3]上获得指针副本的人仍将拥有有效指针

但是,如果您这样做:

client_ptr = &my_vec[3];
客户机是这样解除引用的:

*client_ptr->whatever();

你有问题。现在,当my_vec调整大小时,&my_vec[3]可能不再有效,因此客户端\u ptr指向任何地方。

如果用户要存储指向对象的指针,为什么还要将它们包含在向量中

我觉得在向量中存储指向对象的指针不是一个好主意。我的意思是创建指向向量元素的指针,即my_ptr=&my_vec[n];容器的要点是以容器支持的正常方式引用内容,而不是创建指向容器元素的外部指针

要回答您关于是否可以检测分配的问题,是的,您可以,但是通过指向元素的指针引用向量的内容可能仍然是个坏主意

如果您对向量的最大大小可能增长到什么程度有所了解,那么也可以在创建向量时在向量中保留空间。那么它永远不会调整大小

编辑:

在阅读了其他的回答,并思考了你的问题后,另一个想法出现了。如果向量是指向对象的指针向量,并且将指向对象的指针传递给客户端,则调整向量大小不会使向量所包含的指针无效。问题变成了跟踪拥有它的对象的生命周期,这就是为什么使用shared\u pt r将是有用的

例如:

vector<shared_ptr> my_vec;
my_vec.push_back(stuff);
向量调整大小时不会出现问题。向量的内容将被保留,而my_vec[3]上的内容仍将保留。my_vec[3]指向的对象仍将位于同一地址,my_vec[3]仍将包含该地址。在my_vec[3]上获得指针副本的人仍将拥有有效指针

但是,如果您这样做:

client_ptr = &my_vec[3];
客户机是这样解除引用的:

*client_ptr->whatever();
你有问题。现在,当my_-vec调整大小时,&my_-vec[3]可能不再有效,因此client_-ptr指向任何地方

如果在指针指向的向量中添加了某些内容 超出容量,据我所知,向量将 分配新内存和指向内存中任何元素的每个指针 该向量将变得无效

我曾经写过一些代码来分析当向量的容量超过时会发生什么。你这样做了吗?这段代码在我的Ubuntu和g++v5系统上演示的是std::vector代码只需将容量增加一倍,b将所有元素从旧存储移到新存储,然后c清理旧存储。也许您的实现是类似的。我认为产能扩张的细节取决于实施情况

是的,当push_back导致超出容量时,任何指向向量的指针都将无效

我只是不使用指向向量的指针,你也不应该。这样就完全消除了这个问题,因为它根本不可能发生。另请参见悬挂指针访问std::vector或std::array元素的正确方法是通过运算符[]方法使用索引

在任何容量扩展之后,索引小于先前容量限制的所有元素的索引仍然有效,因为push_back将新元素安装在“end”(我认为最高内存地址)处。元素的内存位置可能已更改,但元素索引仍然相同

2我的做法是不超过容量。是的,我的意思是,我已经能够制定出我的所有问题,以便我知道所需的最大容量。我从未发现这种方法是个问题

3如果向量内容不能包含在系统内存中,我的系统的最佳上限容量约为3.5 GB,那么向量容器或任何基于ram的容器可能不合适。您必须使用磁盘存储来实现您的目标,可能需要使用向量容器作为缓存

2017年7月31日更新

从我最近的生命游戏中考虑的一些代码。< /P> 二维游戏板上的每个单元有8个相邻单元

在我的实现中,每个单元都有一个邻居列表,可以是std::array,也可以是std::vector,我已经尝试了这两种方法,在游戏板完全构建之后,每个单元的init方法都会运行,填充它的邻居列表

// see Cell_t data attributes
std::array<int, 8> m_neighbors;
// ...

void Cell_t::void init()
  {
     int i = 0;
     m_neighbors[i]   = validCellIndx(m_row-1, m_col-1);  // 1 - up left
     m_neighbors[++i] = validCellIndx(m_row-1, m_col);    // 2 - up
     m_neighbors[++i] = validCellIndx(m_row-1, m_col+1);  // 3 - up right
     m_neighbors[++i] = validCellIndx(m_row,   m_col+1);  // 4 - right
     m_neighbors[++i] = validCellIndx(m_row+1, m_col+1);  // 5 - down right
     m_neighbors[++i] = validCellIndx(m_row+1, m_col);    // 6 - down
     m_neighbors[++i] = validCellIndx(m_row+1, m_col-1);  // 7 - down left
     m_neighbors[++i] = validCellIndx(m_row,   m_col-1);  // 8 - left
     //                 ^^^^^^^^^^^^^- returns info to quickly find cell
  }
init预先计算此单元格的索引。m_邻域数组保存索引整数,而不是指针。没有指向游戏板向量的指针是很简单的

如果在指针指向的向量中添加了某些内容 超出容量,据我所知,向量将 分配新内存和指向内存中任何元素的每个指针 该向量将变得无效

我曾经写过一些代码来分析当向量的容量超过时会发生什么。你这样做了吗?这段代码在我的Ubuntu和g++v5系统上演示的是std::vector代码只需将容量增加一倍,b将所有元素从旧存储移到新存储,然后c清理旧存储。也许您的实现是类似的。我认为产能扩张的细节取决于实施情况

是的,当push_back导致超出容量时,任何指向向量的指针都将无效

我只是不使用指向向量的指针,你也不应该。这样就完全消除了这个问题,因为它根本不可能发生。另请参见悬挂指针访问std::vector或std::array元素的正确方法是通过运算符[]方法使用索引

在任何容量扩展之后,索引小于先前容量限制的所有元素的索引仍然有效,因为push_back将新元素安装在“end”(我认为最高内存地址)处。元素的内存位置可能已更改,但元素索引仍然相同

2我的做法是不超过容量。是的,我的意思是,我已经能够制定出我的所有问题,以便我知道所需的最大容量。我从未发现这种方法是个问题

3如果向量内容不能包含在系统内存中,我的系统的最佳上限容量约为3.5 GB,那么向量容器或任何基于ram的容器可能不合适。你将不得不使用 磁盘存储,可能使用向量容器作为缓存

2017年7月31日更新

从我最近的生命游戏中考虑的一些代码。< /P> 二维游戏板上的每个单元有8个相邻单元

在我的实现中,每个单元都有一个邻居列表,可以是std::array,也可以是std::vector,我已经尝试了这两种方法,在游戏板完全构建之后,每个单元的init方法都会运行,填充它的邻居列表

// see Cell_t data attributes
std::array<int, 8> m_neighbors;
// ...

void Cell_t::void init()
  {
     int i = 0;
     m_neighbors[i]   = validCellIndx(m_row-1, m_col-1);  // 1 - up left
     m_neighbors[++i] = validCellIndx(m_row-1, m_col);    // 2 - up
     m_neighbors[++i] = validCellIndx(m_row-1, m_col+1);  // 3 - up right
     m_neighbors[++i] = validCellIndx(m_row,   m_col+1);  // 4 - right
     m_neighbors[++i] = validCellIndx(m_row+1, m_col+1);  // 5 - down right
     m_neighbors[++i] = validCellIndx(m_row+1, m_col);    // 6 - down
     m_neighbors[++i] = validCellIndx(m_row+1, m_col-1);  // 7 - down left
     m_neighbors[++i] = validCellIndx(m_row,   m_col-1);  // 8 - left
     //                 ^^^^^^^^^^^^^- returns info to quickly find cell
  }


init预先计算此单元格的索引。m_邻域数组保存索引整数,而不是指针。没有指向游戏板向量的指针是很简单的

在这种情况下,您可能需要类似std::list或std::deque的内容。您可以做的另一件事是不传递指针,但向量索引不会比指针更糟糕。区别是一个,也许两个,额外的算术运算加上+移位。当然,这比每次回推后的检查、分支和大量指针更新要好得多。我认为我不理解索引的问题。我猜您担心的性能问题并不是什么大问题。或者,你还没有真正跟德克谈过这个问题。迭代会比较慢,但也不会太慢。@CodyGray好吧,当涉及到使用指示符的解决方案时,这不仅仅是性能问题。我认为对于用户/开发人员来说,存储指向对象的指针比存储数字更有意义。但你是对的,替代方案可能不会对性能更好。我不同意。索引更适合于抽象,也更适合于您遇到的问题。一个典型的解决方案是添加间接指针,用指向指针(也称为句柄)的间接指针替换直接指针,以便在必要时将指针移动到后台。索引是一种同样好的抽象。在这种情况下,像std::list或std::deque之类的东西可能是您想要的东西。您可以做的另一件事是不传递指针,但向量索引不会比指针更糟糕。区别是一个,也许两个,额外的算术运算加上+移位。当然,这比每次回推后的检查、分支和大量指针更新要好得多。我认为我不理解索引的问题。我猜您担心的性能问题并不是什么大问题。或者,你还没有真正跟德克谈过这个问题。迭代会比较慢,但也不会太慢。@CodyGray好吧,当涉及到使用指示符的解决方案时,这不仅仅是性能问题。我认为对于用户/开发人员来说,存储指向对象的指针比存储数字更有意义。但你是对的,替代方案可能不会对性能更好。我不同意。索引更适合于抽象,也更适合于您遇到的问题。一个典型的解决方案是添加间接指针,用指向指针(也称为句柄)的间接指针替换直接指针,以便在必要时将指针移动到后台。索引是一个同样好的抽象。例如,您是否尝试过阅读LLVM源代码?他们在几乎每个翻译单元中都使用类似std::vector的东西。这对多态性有用吗?使用一个向量来保存指针很好。分发指向向量元素的指针是我的一个问题。i、 e.my_ptr=&vector[3];例如,您是否曾经尝试过阅读LLVM源代码?他们在几乎每个翻译单元中都使用类似std::vector的东西。这对多态性有用吗?使用一个向量来保存指针很好。分发指向向量元素的指针是我的一个问题。i、 e.my_ptr=&vector[3];超过系统内存容量会导致交换参与,您的性能会受到影响。超过系统内存容量会导致交换参与,您的性能会受到影响。