Valgrind抱怨使用有条件跳跃,这些跳跃取决于非初始化的字节
Valgrind complains about using conditional jumps that depend on uninitialized bytes
我有这个问题出现在我正在处理的较大程序的模块中,这是一个小模拟:
#include <iostream>
#include <vector>
using namespace std;
struct node{
int key;
vector<int> connections;
};
int main(void){
int size = 10;
node *A;
A=(node*)malloc((size)*sizeof(node));
int i;
for(i=0;i<size;i++){
A[i].key = i;
if(i%2 == 0) A[i].connections.push_back(i);
}
for(i=0;i<size;i++) {
if(A[i].connections.size() > 0) {
cout << A[i].key << "---" << A[i].connections.size() << endl;
}
}
free(A);
return 0;
}
这是我运行valgrind ./testCode
==30433== Conditional jump or move depends on uninitialised value(s)
==30433== at 0x400F63: std::vector<int, std::allocator<int> >::push_back(int const&) (stl_vector.h:915)
==30433== by 0x400DF0: main (testCode.cpp:25)
从我的理解中,问题是,在矢量的push_back
函数内有一个IF语句,它使用了某些非传统的值。我不确定到底是什么。玩耍后,事实证明我使用malloc
。如果我使用calloc
,我根本不会收到任何警告。如果我使用new
,也是如此。但是,在所有情况下,该程序的行为完全相同。这里发生了什么?即使我收到所有这些警告,也可以安全使用malloc
吗?
不,在这里使用malloc
是不安全的。
malloc
是分配内存的C方式。它不考虑C 构造函数。
calloc
也是C,但它使您的内存零零。这就是std::vector
工作的原因(但是,这也是未定义的行为,因为可能有一个vector
实现,需要将其初始化为零以外的其他功能)。
有很多方法可以解决这个问题:
-
使用
new Node
代替。 -
如果您不能这样做,则至少可以在
malloc
返回的内存上进行新的位置(new (ptr) Node()
)。 -
使用智能指针和
make_shared
或make_unique
。这样,您甚至不需要照顾释放记忆。 -
最好的方法可能是使用
std::vector
(如另一个答案中建议)或std::array
。
由于您使用的是vector&lt;>,因此您应该始终避免使用malloc且免费
但是,很少有需要使用新/删除,因为向量在相似的内存和访问足迹的情况下完成了相同的事情。
此实现将node
包装在向量中,并消除直接内存分配,因为它是通过向量&lt;>自动完成的,同时保持了相同的传统用法样式。
#include <iostream>
#include <vector>
using namespace std;
struct node {
int key;
vector<int> connections;
};
int main(void) {
// original with similar memory footprint and access characteristics using modern C++ vector<>
int size = 10;
vector<node> A(size);
int i;
for (i = 0; i<size; i++) {
A[i].key = i;
if (i % 2 == 0) A[i].connections.push_back(i);
}
for (i = 0; i<size; i++) {
if (A[i].connections.size() > 0) {
cout << A[i].key << "---" << A[i].connections.size() << endl;
}
}
return 0;
}
可能是因为malloc
不调用node
的构造函数。由于这是C ,因此node
不是C中的结构,而是一个类。它具有一个隐式构造函数,需要在实例化时调用。这意味着向量也无法正确创建。
您应该做2件事:
- 避免致电新,在这种情况下不需要,只需使用
node A[10]
或更好的std::vector<node> A
。 - 如果您不能这样做,请务必在C 中使用
new
,以便正确创建对象。
如果您绝对必须使用malloc
,则需要调用placement new
以构建您的结构(new (&A[0]) node()
),因此实际上只是不使用malloc
。
未设置节点内的连接。这是因为您使用malloc创建YR节点实例。这只是为您提供了原始的非初始化内存。您必须使用新的来分配C 程序中的对象,而不是Malloc。新的分配内存然后运行构造函数
IE
node *A = new Node();
并删除以释放它 - 不免费
实际上您需要一个节点对象。那做本说的。制作它们的向量
但是,无论如何,除非您真的确定自己在做什么
- 重载运算符new[]的行为取决于析构函数
- 新的放置取决于 iostream
- Writefile() 无法写入数据,具体取决于数据的长度
- ASIO signal_set多个 IO 线程不可靠,具体取决于代码顺序?
- SFINAE是否取决于类型推断?
- 将强制转换简化为取决于参数的类型
- 修复"-Wunused-parameter"取决于预处理器条件的警告
- 内存中类位置的成员是否取决于类成员在类定义中的位置?
- 奇怪的Arduino C++编译错误取决于文件位置
- CUDA 的性能取决于声明变量
- 我想要一个具有子函数的函数访问相同的命名函数,而不使用它取决于其子类的类
- 条件跳转或移动取决于 std::wistringstream 的未初始化值
- cpp 模板专用化,错误说参数 1 的类型为 T,这取决于参数 T
- 为什么c++中类的大小取决于数据成员的公共/私有状态
- 编译时函数的选择取决于类型大小
- memcpy是否取决于源指针和目标指针的类型
- 检查是否至少设置了一点而不跳跃
- 矩阵乘法的速度取决于愚蠢的事情
- 如果条件取决于模板类型并且在编译时已知,是否可以保证C++编译器不会生成分支?
- Valgrind抱怨使用有条件跳跃,这些跳跃取决于非初始化的字节