当推送一个新对象时,指向该对象的指针将变成垃圾
When pushing a new object, a pointer to that object becomes garbage
当我从映射中的向量推送对对象的引用时,引用向量中的前一个值会变成垃圾,但原始对象不会。
以下是再现问题的最小代码:
#include <iostream>
#include <vector>
#include <map>
#include <string>
class foo
{
private:
std::map<std::string, std::vector<int>> _allObjs;
std::vector<int*> _someObjs;
public:
void addObj(const std::string &name, int obj)
{
_allObjs[name].push_back(obj);
_someObjs.push_back(&_allObjs[name].back());
}
void doStuff()
{
for (auto &obj : _someObjs)
{
std::cout << *obj << std::endl;
}
}
};
int main()
{
foo test;
test.addObj("test1", 5);
test.addObj("test1", 6);
test.addObj("test2", 7);
test.addObj("test2", 8);
test.doStuff();
}
Expected Output
5
6
7
8
Actual Output
-572662307
6
-572662307
8
在调试它时,我发现只要我把对象推到addObj中的_allObjs
,指针就会变成垃圾。我不知道是什么原因造成的,所以我帮不了什么忙。谢谢
向量将其数据存储在连续的内存块中。
当您想要存储超出其当前容量的内容时,它将分配一个新的、更大的连续内存块,并将所有现有元素从上一个内存块复制/移动到新的内存块中。
当您存储指向int(&_allObjs[name].back()
)的指针时,您将把int
的内存地址存储在这些内存块之一中。
一旦向量增长到需要创建额外空间的大小,所有这些内存地址都将指向已释放的地址。访问它们是未定义的行为。
让我们看看这个参考页面对向向量插入新对象的说明:
如果新的size()大于capacity(),则所有迭代器和引用(包括过去的结束迭代器)都将无效。否则,只有过去的结束迭代器无效。
因此,当您添加新对象时,以前存储的指向同一向量中对象的指针可能会变为无效,即它们不再指向有效对象(除非您确保没有超过容量,但您没有超过)。
中的指针
std::vector<int*> _someObjs;
不稳定。
当你使用
_allObjs[name].push_back(obj);
先前获得的任何地址都可能由于重新分配而无效。
如参考文献所述:
如果新的
size()
大于capacity()
,则所有迭代器和引用(包括过去的结束迭代器)都无效。否则,只有过去的结束迭代器无效。
正如其他人正确提到的,向vector
添加项可能会使迭代器和引用在调整vector
的大小时无效。
如果你想用最少的代码更改快速缓解这种情况,请从更改
std::map<std::string, std::vector<int>>
至
std::map<std::string, std::forward_list<int>>
或std::map<std::string, std::list<int>>
由于std::list / std::forward_list
在调整列表大小时不会使迭代器和引用无效,因此上述场景应该有效(唯一无效的迭代器是指向已从列表中删除的项的迭代者)。
使用std::list
的示例
注意,缺点是与std::vector
不同,链表的使用不会将项目存储在连续内存中,并且std::list
占用更多内存。
这:_allObjs[name].push_back(obj);
(和其他push_back
)可能会使vector
中的所有迭代器(和指针)无效。之后,您不能对进行任何假设。
- 对象指针在c++中是如何工作的
- C++ 对象指针数组的复制构造函数
- 在对象指针上调用 Delete 是否会递归删除其动态分配的成员
- 什么更好?返回对象指针列表?或返回指向对象列表的指针?
- 正确初始化和销毁对象指针的C++数组?
- 如何深度复制链表对象指针
- 对象指针 c++ 的全局向量错误
- 如何将 c++ 类包装到 python 中,以便我可以使用 pybind11 访问其成员的公共方法(成员是一个对象指针)
- 静态对象指针
- 正在将对象指针数组初始化为NULL
- 如何使用条件表达式返回对象指针?
- std::flush可以用于将对象指针转换为其封闭数组指针吗
- 使用C对象指针构建PyObject*
- 如何在使用对象指针时访问成员函数
- 静态强制转换允许转换对象指针,但不允许转换整数
- C++ abort() 在函数内的抽象类对象指针调用上
- 指向函数的对象指针
- 访问指向对象指针向量的指针的第一个元素?
- 如何将对象/指针正确存储到 Qlist 中
- 对象指针打印结果以相反的顺序进行