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 来创建您的 Node 实例。那只会给你原始的未初始化内存。你必须使用 new 在 c++ 程序中分配对象而不是 malloc。 New 分配内存然后运行构造函数
即
node *A = new Node();
并删除以释放它 - 不是免费的
事实上,您需要一个 Node 对象数组。所以按照本所说的去做。制作它们的矢量
但是无论如何,永远不要在 C++ 程序中使用 malloc / free 除非你真的确定你知道你在做什么
很有可能是因为malloc
没有调用node
的构造函数。由于这是 c++,node
不是 c 中的结构,而是 class。它有一个隐式构造函数,需要在实例化时调用。这意味着向量也没有正确创建。
你应该做两件事:
- 避免调用 new,在这种情况下没有必要,只需使用
node A[10]
或更好的 std::vector<node> A
。
- 如果您不能这样做,请始终在 C++ 中使用
new
,以便正确创建对象。
如果你绝对必须使用 malloc
,那么无论如何你都需要调用 placement new
来构建你的结构 (new (&A[0]) node()
),所以真的不要使用 malloc
.
不,这里使用malloc
不安全。
malloc
是C分配内存的方式。它不考虑 C++ 构造函数。
calloc
也是 C,但它会零初始化您的内存。这就是 std::vector
起作用的原因(然而,它也是未定义的行为,因为可能有一个 vector
实现需要初始化为非零的其他值)。
有很多方法可以解决这个问题:
改用new Node
。
如果你做不到,你至少可以在 malloc
returns (new (ptr) Node()
).[=22= 的内存上做一个新的放置]
使用智能指针和make_shared
或make_unique
。这样一来,您甚至不需要考虑释放内存。
最好的方法可能是使用 std::vector
(如另一个答案中所建议的)或 std::array
.
由于您使用的是 vector<>,因此您应该始终避免使用 malloc 和 free,因为它们不会初始化构造函数,而是使用 new 和 delete 以及智能指针。
但是,很少需要使用 new/delete,因为 vector 使用类似的内存和访问足迹完成同样的事情。
此实现将 node
包装在向量中并消除了直接内存分配,因为它由 vector<> 自动完成,同时保持相同的传统使用方式。
#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;
}
这个问题出现在我正在处理的一个较大程序的模块中,这里是一个小模拟:
#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 来创建您的 Node 实例。那只会给你原始的未初始化内存。你必须使用 new 在 c++ 程序中分配对象而不是 malloc。 New 分配内存然后运行构造函数
即
node *A = new Node();
并删除以释放它 - 不是免费的
事实上,您需要一个 Node 对象数组。所以按照本所说的去做。制作它们的矢量
但是无论如何,永远不要在 C++ 程序中使用 malloc / free 除非你真的确定你知道你在做什么
很有可能是因为malloc
没有调用node
的构造函数。由于这是 c++,node
不是 c 中的结构,而是 class。它有一个隐式构造函数,需要在实例化时调用。这意味着向量也没有正确创建。
你应该做两件事:
- 避免调用 new,在这种情况下没有必要,只需使用
node A[10]
或更好的std::vector<node> A
。 - 如果您不能这样做,请始终在 C++ 中使用
new
,以便正确创建对象。
如果你绝对必须使用 malloc
,那么无论如何你都需要调用 placement new
来构建你的结构 (new (&A[0]) node()
),所以真的不要使用 malloc
.
不,这里使用malloc
不安全。
malloc
是C分配内存的方式。它不考虑 C++ 构造函数。
calloc
也是 C,但它会零初始化您的内存。这就是 std::vector
起作用的原因(然而,它也是未定义的行为,因为可能有一个 vector
实现需要初始化为非零的其他值)。
有很多方法可以解决这个问题:
改用
new Node
。如果你做不到,你至少可以在
malloc
returns (new (ptr) Node()
).[=22= 的内存上做一个新的放置]使用智能指针和
make_shared
或make_unique
。这样一来,您甚至不需要考虑释放内存。最好的方法可能是使用
std::vector
(如另一个答案中所建议的)或std::array
.
由于您使用的是 vector<>,因此您应该始终避免使用 malloc 和 free,因为它们不会初始化构造函数,而是使用 new 和 delete 以及智能指针。
但是,很少需要使用 new/delete,因为 vector 使用类似的内存和访问足迹完成同样的事情。
此实现将 node
包装在向量中并消除了直接内存分配,因为它由 vector<> 自动完成,同时保持相同的传统使用方式。
#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;
}