I'm a new C++ coder and met a problem.
Please view the following code as an example:
#include <iostream>
#include <vector>
#include <thread>
class student{
public:
std::string name;
int id;
};
void foo(){
int k = 1;
std::cout<<"thread a"<<std::endl;
return;
}
void foo2(){
int k = 1;
std::cout<<"thread b"<<std::endl;
return;
}
void foo3(){
std::thread a(foo);
std::thread b(foo2);
a.detach();
b.detach();
return;
}
int main(){
foo3();
return 0;
}
That's an example code. I want two threads running independently and release memory after each one ends. I use valgrind to check memory leak. It shows an error like this:
==63346== Memcheck, a memory error detector
==63346== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==63346== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==63346== Command: ./a.out
==63346==
==63346==
==63346== HEAP SUMMARY:
==63346== in use at exit: 608 bytes in 4 blocks
==63346== total heap usage: 5 allocs, 1 frees, 73,312 bytes allocated
==63346==
==63346== 288 bytes in 1 blocks are possibly lost in loss record 3 of 4
==63346== at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==63346== by 0x40147D9: calloc (rtld-malloc.h:44)
==63346== by 0x40147D9: allocate_dtv (dl-tls.c:375)
==63346== by 0x40147D9: _dl_allocate_tls (dl-tls.c:634)
==63346== by 0x4B4D834: allocate_stack (allocatestack.c:430)
==63346== by 0x4B4D834: pthread_create##GLIBC_2.34 (pthread_create.c:647)
==63346== by 0x494A388: std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==63346== by 0x1095B9: std::thread::thread<void (&)(), , void>(void (&)()) (in /home/alan/Avionics/test/a.out)
==63346== by 0x10935C: foo3() (in /home/alan/Avionics/test/a.out)
==63346== by 0x109400: main (in /home/alan/Avionics/test/a.out)
==63346==
==63346== 288 bytes in 1 blocks are possibly lost in loss record 4 of 4
==63346== at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==63346== by 0x40147D9: calloc (rtld-malloc.h:44)
==63346== by 0x40147D9: allocate_dtv (dl-tls.c:375)
==63346== by 0x40147D9: _dl_allocate_tls (dl-tls.c:634)
==63346== by 0x4B4D834: allocate_stack (allocatestack.c:430)
==63346== by 0x4B4D834: pthread_create##GLIBC_2.34 (pthread_create.c:647)
==63346== by 0x494A388: std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==63346== by 0x1095B9: std::thread::thread<void (&)(), , void>(void (&)()) (in /home/alan/Avionics/test/a.out)
==63346== by 0x109372: foo3() (in /home/alan/Avionics/test/a.out)
==63346== by 0x109400: main (in /home/alan/Avionics/test/a.out)
==63346==
==63346== LEAK SUMMARY:
==63346== definitely lost: 0 bytes in 0 blocks
==63346== indirectly lost: 0 bytes in 0 blocks
==63346== possibly lost: 576 bytes in 2 blocks
==63346== still reachable: 32 bytes in 2 blocks
==63346== suppressed: 0 bytes in 0 blocks
==63346== Reachable blocks (those to which a pointer was found) are not shown.
==63346== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==63346==
==63346== For lists of detected and suppressed errors, rerun with: -s
==63346== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
If i replace detach() by join(), there's no memory leak, I'm a little confused. Does anyone can give me some advice? Thanks a lot!
You need to make your main wait until the threads have finished running (or at least that they won't access any global objects after). If you don't make sure of that, not only will you have memory leaks, you may also have undefined behavior.
join does exactly make sure of that. The thread calling it will wait until the thread on which join is called finishes.
On the other hand detach is used to when you don't want to keep the std::thread object around to call join on it, while still having the thread function continue to run. If you detach a thread you need to use some other synchronization mechanism outside the join mechanism to make sure that main doesn't exit while the threads are still doing work (or at least accessing global objects).
There is rarely a need to detach a thread. Making it work is complicated. You don't need to do that.
Instead store the std::thread object somewhere and call join on it when you want to wait for your threads to end, at latest before main returns. That should be the default approach if you don't have a good reason to not use it. If you are a beginner, then you can forget about detach for now.
I'm testing c++17 shared_ptr to see how it handles array delete[], but it failed expectation.
First, c++17 document says shared_ptr<T[]> can handle delete[] properly.
http://eel.is/c++draft/util.smartptr.shared#const-5
Effects: When T is not an array type, constructs a shared_ptr object that owns the pointer p. Otherwise, constructs a shared_ptr that owns p and a deleter of an unspecified type that calls delete[] p.
And reset():
http://eel.is/c++draft/util.smartptr.shared#mod-3
Equivalent to shared_ptr(p).swap(*this).
It will transfer the specification-required custom delete. So from my understanding, pre-c++17 I have to write like this:
shared_ptr<int> t1(new int[7], default_delete<int[]>());
Now it knows when 1st parameter is array type, compiler will generate call to delete [], so that we no longer have to specify delete function explicitly. I had a quick test on Ubuntu20.04 with clang++13:
int main() {
shared_ptr<int> t1(new int[7], default_delete<int[]>());
return 0;
}
Then clang++ mytest.cpp && valgrind ./a.out, no problem. But if I change to:
int main() {
shared_ptr<int> t1(new int[7]);
return 0;
}
Then clang++ mytest.cpp -std=c++17 && valgrind ./a.out will print:
==16407== Command: ./a.out
==16407==
Father
1
==16407== Mismatched free() / delete / delete []
==16407== at 0x483CFBF: operator delete(void*) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16407== by 0x40450A: std::_Sp_counted_ptr<int*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (in /home/troskyv/a.out)
==16407== by 0x4030A2: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (in /home/troskyv/a.out)
==16407== by 0x403059: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() (in /home/troskyv/a.out)
==16407== by 0x403998: std::__shared_ptr<int, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() (in /home/troskyv/a.out)
==16407== by 0x4020C4: std::shared_ptr<int>::~shared_ptr() (in /home/troskyv/a.out)
==16407== by 0x40152E: main (in /home/troskyv/a.out)
==16407== Address 0x4db34c0 is 0 bytes inside a block of size 28 alloc'd
==16407== at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16407== by 0x4014F7: main (in /home/troskyv/a.out)
==16407==
==16407==
==16407== HEAP SUMMARY:
==16407== in use at exit: 0 bytes in 0 blocks
==16407== total heap usage: 15 allocs, 15 frees, 74,032 bytes allocated
==16407==
==16407== All heap blocks were freed -- no leaks are possible
==16407==
==16407== For lists of detected and suppressed errors, rerun with: -s
==16407== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
There's memory leak. So seems to me although I used -std=c++17 option, shared_ptr still cannot handle delete array automatically.
Where did this get wrong?
I see the answer is difference between shared_ptr<int> and shared_ptr<int[]>. Use of the latter one avoids memory leak.
Thanks, close this question!
So I'm implementing a weighted digraph with templates using a dynamic matrix (which I also implemented).
The thing is, when I use my Matrix class on its own it works fine, but inside the Graph class it just doesn't and I don't understand why. I was hoping someone could help me out.
Here is the Matrix class. I tested it directly on main.cpp with Valgrind and it didn't show anything.
template <typename Type>
class Matrix {
private:
Type** matrix;
unsigned size;
Type null;
public:
Matrix();
Matrix(unsigned size, Type null);
Matrix(const Matrix& matrix);
~Matrix();
Type getData(unsigned row, unsigned col);
void insert(Type data, unsigned row, unsigned col);
void freeMatrixResources(Type** matrix);
void resize(unsigned size);
void assignNull(unsigned int beginRow, unsigned int endRow, unsigned int beginCol, unsigned int endCol);
void copyData(Type** matrix, unsigned begin, unsigned end);
void printMatrix();
Type operator()(unsigned int row, unsigned int col);
friend ostream& operator << (ostream& o, const Matrix<Type> &m);
};
template <typename Type>
ostream& operator << (ostream& out, const Matrix<Type> &m) {
for (int i = 0; i < m.size; ++i) {
out << "\t\t";
for (int j = 0; j < m.size; ++j) {
out << m.getData(i, j) << "\t";
}
out << "\n";
}
out << "\n";
return out;
}
template <typename Type>
Type Matrix<Type>:: operator()(unsigned int row, unsigned int col) {
return matrix[row][col];
}
template <typename Type>
Matrix<Type>:: Matrix() {
matrix = 0;
size = 0;
null = 0;
}
template <typename Type>
Matrix<Type>:: Matrix(unsigned size, Type null) {
matrix = new Type*[size];
for (int i = 0; i < size; ++i)
matrix[i] = new Type[size];
this->size = size;
this->null = null;
assignNull(0, size, 0, size);
}
template <typename Type>
Matrix<Type>:: Matrix(const Matrix<Type> &matrix) {
this->matrix = new Type*[matrix.size];
for (int i = 0; i < matrix.size; ++i)
matrix[i] = new Type[matrix.size];
copyData(matrix,0,0);
}
template <typename Type>
Matrix<Type>:: ~Matrix() {
freeMatrixResources(matrix);
}
template <typename Type>
Type Matrix<Type>:: getData(unsigned row, unsigned col) {
return matrix[row][col];
}
template <typename Type>
void Matrix<Type>:: insert(Type data, unsigned int row, unsigned int col) {
matrix[row][col] = data;
}
template <typename Type>
void Matrix<Type>:: freeMatrixResources(Type** matrix) {
for (int i = 0; i < size; ++i) {
delete [] matrix[i];
}
delete [] matrix;
}
template <typename Type>
void Matrix<Type>:: resize(unsigned int newSize) {
if (this->size != newSize) {
Type** aux = matrix;
matrix = new Type*[newSize];
for (int i = 0; i < newSize; ++i)
matrix[i] = new Type[newSize];
if (this->size < newSize) {
copyData(aux, 0, this->size);
assignNull(this->size, newSize, 0, newSize);
assignNull(0, newSize, this->size, newSize);
}
else
copyData(aux, 0, newSize);
freeMatrixResources(aux);
this->size = newSize;
}
}
template <typename Type>
void Matrix<Type>:: assignNull(unsigned int beginRow, unsigned int endRow, unsigned int beginCol, unsigned int endCol) {
for (int i = beginRow; i < endRow; ++i) {
for (int j = beginCol; j < endCol; ++j) {
matrix[i][j] = null;
}
}
}
template <typename Type>
void Matrix<Type>:: copyData(Type** matrix, unsigned int begin, unsigned int end) {
for (int i = begin; i < end; ++i) {
for (int j = begin; j < end; ++j) {
this->matrix[i][j] = matrix[i][j];
}
}
}
template <typename Type>
void Matrix<Type>:: printMatrix() {
for (int i = 0; i < size; ++i) {
cout << "\t\t";
for (int j = 0; j < size; ++j) {
cout << matrix[i][j] << "\t";
}
cout << "\n";
}
cout << "\n";
}
But then, when I run the Graph program with valgrind --tool=memcheck --leak-check=full "./cmake-build-debug/graphTemplates" the output says Uninitialised value was created by a stack allocation, Conditional jump or move depends on uninitialised value(s)
==155342== Memcheck, a memory error detector
==155342== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==155342== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==155342== Command: ./cmake-build-debug/graphTemplates
==155342==
==155342== Conditional jump or move depends on uninitialised value(s)
==155342== at 0x109BEC: Matrix<int>::resize(unsigned int) (Matrix.h:100)
==155342== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155342== by 0x109327: main (main.cpp:36)
==155342==
==155342== Conditional jump or move depends on uninitialised value(s)
==155342== at 0x109C0D: Matrix<int>::resize(unsigned int) (Matrix.h:103)
==155342== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155342== by 0x109327: main (main.cpp:36)
==155342==
==155342== Conditional jump or move depends on uninitialised value(s)
==155342== at 0x483C530: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==155342== by 0x109C1A: Matrix<int>::resize(unsigned int) (Matrix.h:103)
==155342== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155342== by 0x109327: main (main.cpp:36)
==155342==
==155342== Conditional jump or move depends on uninitialised value(s)
==155342== at 0x109C39: Matrix<int>::resize(unsigned int) (Matrix.h:104)
==155342== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155342== by 0x109327: main (main.cpp:36)
==155342==
==155342== Conditional jump or move depends on uninitialised value(s)
==155342== at 0x109C4B: Matrix<int>::resize(unsigned int) (Matrix.h:105)
==155342== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155342== by 0x109327: main (main.cpp:36)
==155342==
==155342== Conditional jump or move depends on uninitialised value(s)
==155342== at 0x483C530: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==155342== by 0x109C74: Matrix<int>::resize(unsigned int) (Matrix.h:105)
==155342== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155342== by 0x109327: main (main.cpp:36)
==155342==
==155342== Conditional jump or move depends on uninitialised value(s)
==155342== at 0x109C88: Matrix<int>::resize(unsigned int) (Matrix.h:107)
==155342== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155342== by 0x109327: main (main.cpp:36)
==155342==
==155342== Conditional jump or move depends on uninitialised value(s)
==155342== at 0x109D51: Matrix<int>::assignNull(unsigned int, unsigned int, unsigned int, unsigned int) (Matrix.h:122)
==155342== by 0x109CC8: Matrix<int>::resize(unsigned int) (Matrix.h:109)
==155342== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155342== by 0x109327: main (main.cpp:36)
==155342==
==155342== Conditional jump or move depends on uninitialised value(s)
==155342== at 0x109D5F: Matrix<int>::assignNull(unsigned int, unsigned int, unsigned int, unsigned int) (Matrix.h:123)
==155342== by 0x109CC8: Matrix<int>::resize(unsigned int) (Matrix.h:109)
==155342== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155342== by 0x109327: main (main.cpp:36)
==155342==
==155342== Conditional jump or move depends on uninitialised value(s)
==155342== at 0x109D51: Matrix<int>::assignNull(unsigned int, unsigned int, unsigned int, unsigned int) (Matrix.h:122)
==155342== by 0x109CE9: Matrix<int>::resize(unsigned int) (Matrix.h:110)
==155342== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155342== by 0x109327: main (main.cpp:36)
==155342==
==155342== Conditional jump or move depends on uninitialised value(s)
==155342== at 0x109D5F: Matrix<int>::assignNull(unsigned int, unsigned int, unsigned int, unsigned int) (Matrix.h:123)
==155342== by 0x109CE9: Matrix<int>::resize(unsigned int) (Matrix.h:110)
==155342== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155342== by 0x109327: main (main.cpp:36)
==155342==
==155342== Use of uninitialised value of size 8
==155342== at 0x109A5E: Matrix<int>::insert(int, unsigned int, unsigned int) (Matrix.h:87)
==155342== by 0x109794: Graph<int, int>::addEdge(int, int, int) (Graph.h:121)
==155342== by 0x109327: main (main.cpp:36)
==155342==
Edge connecting 3 and 1 with cost 7 added successfully!
==155342== Conditional jump or move depends on uninitialised value(s)
==155342== at 0x109EB3: Matrix<int>::freeMatrixResources(int**) (Matrix.h:92)
==155342== by 0x109A99: Matrix<int>::~Matrix() (Matrix.h:77)
==155342== by 0x10958E: Graph<int, int>::~Graph() (Graph.h:84)
==155342== by 0x10934B: main (main.cpp:30)
==155342==
==155342==
==155342== HEAP SUMMARY:
==155342== in use at exit: 0 bytes in 0 blocks
==155342== total heap usage: 14 allocs, 14 frees, 73,900 bytes allocated
==155342==
==155342== All heap blocks were freed -- no leaks are possible
==155342==
==155342== Use --track-origins=yes to see where uninitialised values come from
==155342== For lists of detected and suppressed errors, rerun with: -s
==155342== ERROR SUMMARY: 35 errors from 13 contexts (suppressed: 0 from 0)
valentina#valentina-Lenovo-Yoga-C740-14IML:~/Documentos/Algo II/Plantillvalentina#valentina-Lenovo-Yoga-C740-14IML:~/Documentos/Algo II/Plantillvalentina#valentina-Lenovo-Yoga-C740-14IML:~/Documentos/Algo II/Plantillvalentina#valentina-Lenovo-Yoga-C740-14IML:~/Documentos/Algo II/Plantillas de estructuras/graphTemplates$ v
algrind --tool=memcheck --xml=yes --xml-file=/tmp/valgrind --leak-check=full "./cmake-build-debug/graphTemplates"
========================= GRAPH ================================
Edge connecting 1 and 2 with cost 5 added successfully!
9999999 5
9999999 9999999
Edge connecting 1 and 2 with cost 4 added successfully!
Edge connecting 3 and 1 with cost 7 added successfully!
================================================================
valentina#valentina-Lenovo-Yoga-C740-14IML:~/Documentos/Algo II/Plantillas de estructuras/graphTemplates$ valgrind --tool=memcheck --track-origins=yes --leak-check=full "./cmake-build-debug/graphTemplates"==155816== Memcheck, a memory error detector
==155816== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==155816== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==155816== Command: ./cmake-build-debug/graphTemplates
==155816==
========================= GRAPH ================================
Edge connecting 1 and 2 with cost 5 added successfully!
9999999 5
9999999 9999999
Edge connecting 1 and 2 with cost 4 added successfully!
==155816== Conditional jump or move depends on uninitialised value(s)
==155816== at 0x109BEC: Matrix<int>::resize(unsigned int) (Matrix.h:100)
==155816== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155816== by 0x109327: main (main.cpp:36)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816== Conditional jump or move depends on uninitialised value(s)
==155816== at 0x109C0D: Matrix<int>::resize(unsigned int) (Matrix.h:103)
==155816== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155816== by 0x109327: main (main.cpp:36)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816== Conditional jump or move depends on uninitialised value(s)
==155816== at 0x483C530: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==155816== by 0x109C1A: Matrix<int>::resize(unsigned int) (Matrix.h:103)
==155816== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155816== by 0x109327: main (main.cpp:36)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816== Conditional jump or move depends on uninitialised value(s)
==155816== at 0x109C39: Matrix<int>::resize(unsigned int) (Matrix.h:104)
==155816== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155816== by 0x109327: main (main.cpp:36)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816== Conditional jump or move depends on uninitialised value(s)
==155816== at 0x109C4B: Matrix<int>::resize(unsigned int) (Matrix.h:105)
==155816== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155816== by 0x109327: main (main.cpp:36)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816== Conditional jump or move depends on uninitialised value(s)
==155816== at 0x483C530: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==155816== by 0x109C74: Matrix<int>::resize(unsigned int) (Matrix.h:105)
==155816== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155816== by 0x109327: main (main.cpp:36)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816== Conditional jump or move depends on uninitialised value(s)
==155816== at 0x109C88: Matrix<int>::resize(unsigned int) (Matrix.h:107)
==155816== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155816== by 0x109327: main (main.cpp:36)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816== Conditional jump or move depends on uninitialised value(s)
==155816== at 0x109D51: Matrix<int>::assignNull(unsigned int, unsigned int, unsigned int, unsigned int) (Matrix.h:122)
==155816== by 0x109CC8: Matrix<int>::resize(unsigned int) (Matrix.h:109)
==155816== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155816== by 0x109327: main (main.cpp:36)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816== Conditional jump or move depends on uninitialised value(s)
==155816== at 0x109D5F: Matrix<int>::assignNull(unsigned int, unsigned int, unsigned int, unsigned int) (Matrix.h:123)
==155816== by 0x109CC8: Matrix<int>::resize(unsigned int) (Matrix.h:109)
==155816== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155816== by 0x109327: main (main.cpp:36)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816== Conditional jump or move depends on uninitialised value(s)
==155816== at 0x109D51: Matrix<int>::assignNull(unsigned int, unsigned int, unsigned int, unsigned int) (Matrix.h:122)
==155816== by 0x109CE9: Matrix<int>::resize(unsigned int) (Matrix.h:110)
==155816== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155816== by 0x109327: main (main.cpp:36)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816== Conditional jump or move depends on uninitialised value(s)
==155816== at 0x109D5F: Matrix<int>::assignNull(unsigned int, unsigned int, unsigned int, unsigned int) (Matrix.h:123)
==155816== by 0x109CE9: Matrix<int>::resize(unsigned int) (Matrix.h:110)
==155816== by 0x10974B: Graph<int, int>::addEdge(int, int, int) (Graph.h:119)
==155816== by 0x109327: main (main.cpp:36)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816== Use of uninitialised value of size 8
==155816== at 0x109A5E: Matrix<int>::insert(int, unsigned int, unsigned int) (Matrix.h:87)
==155816== by 0x109794: Graph<int, int>::addEdge(int, int, int) (Graph.h:121)
==155816== by 0x109327: main (main.cpp:36)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816== Conditional jump or move depends on uninitialised value(s)
==155816== at 0x109EB3: Matrix<int>::freeMatrixResources(int**) (Matrix.h:92)
==155816== by 0x109A99: Matrix<int>::~Matrix() (Matrix.h:77)
==155816== by 0x10958E: Graph<int, int>::~Graph() (Graph.h:84)
==155816== by 0x10934B: main (main.cpp:30)
==155816== Uninitialised value was created by a stack allocation
==155816== at 0x109289: main (main.cpp:7)
==155816==
==155816==
==155816== HEAP SUMMARY:
==155816== in use at exit: 0 bytes in 0 blocks
==155816== total heap usage: 14 allocs, 14 frees, 73,900 bytes allocated
==155816==
==155816== All heap blocks were freed -- no leaks are possible
==155816==
==155816== For lists of detected and suppressed errors, rerun with: -s
==155816== ERROR SUMMARY: 35 errors from 13 contexts (suppressed: 0 from 0)
Here are the methods in the Graph class which Valgrind complains
template<typename Type, typename Cost>
Graph<Type, Cost>:: ~Graph() {
delete costsMatrix;
delete vertices;
}
template<typename Type, typename Cost>
void Graph<Type, Cost>:: addEdge(Type begin, Type end, Cost cost) {
if (existsVertex(begin) && existsVertex(end)) {
costsMatrix->insert(cost, vertices->getPosition(begin), vertices->getPosition(end));
}
else if (existsVertex(begin)) {
costsMatrix->resize(elements + 1);
vertices->insertAtEnd(end);
costsMatrix->insert(cost, vertices->getPosition(begin), elements);
elements += 1;
}
else if(existsVertex(end)) {
costsMatrix->resize(elements + 1);
vertices->insertAtEnd(begin);
costsMatrix->insert(cost, elements, vertices->getPosition(end));
elements += 1;
}
else {
costsMatrix->resize(elements + 2);
vertices->insertAtEnd(begin);
vertices->insertAtEnd(end);
elements += 2;
costsMatrix->insert(cost, vertices->getPosition(begin), vertices->getPosition(end));
}
cout << "\t\tEdge connecting " << begin << " and " << end << " with cost " << cost << " added successfully!\n";
}
I know I could use std library for the matrix, but I was asked not to
Update: The problem was that in one of the paths I had, I was not initializing the attribute elements correctly. Thanks all for the help
The error says that there's an uninitialized value being used in a "conditional jump or move", which basically means a conditional statement such as if. It says that the error is happening the Matrix<int>::resize(unsigned int) method. So it must be referring to
if (this->size != newSize)
which means that either this->size or newSize is uninitialized.
Another valgrind error says that an uninitialized value is being used in operator new[](unsigned long) being called from the resize method. So that must be referring to
matrix = new Type*[newSize];
So this has narrowed down the problem to the newSize variable. This is a function parameter, so we have to step back to where the function is called. The stack trace says it was called from Graph<int, int>::addEdge(int, int, int). All the calls are similar to:
costsMatrix->resize(elements + 1);
so the problem must be that the elements variable is not initialized.
I want to understand the valgrind log messages and use the following code
#include <iostream>
int main()
{
int numbers[] = {1,2,3,4,5,6,7,8,9,10};
int length = sizeof(numbers) / sizeof(numbers[0]);
std::cout << "length: " << length << std::endl;
for (int i = 0; i < length + 10; ++i)
{
int number = numbers[i];
if (number > 5)
{
std::cout << number << " is greater than 5" << std::endl;
} else {
std::cout << number << " is less or equal 5" << std::endl;
}
}
}
to produce uninitialised values. If I run the program in valgrind I don't receive a corresponding message. If I run the for-loop to length + 10 valgrind detects uninitialised values.
Why does valgrind detect the unitialised values only so late?
==2484== Conditional jump or move depends on uninitialised value(s)
==2484== at 0x108A3C: main (arrays.cpp:11)
==2484== Uninitialised value was created by a stack allocation
==2484== at 0x51E6ABB: (below main) (libc-start.c:137)
==2484==
==2484== Conditional jump or move depends on uninitialised value(s)
==2484== at 0x4F43C0A: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x4F501A4: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x108A85: main (arrays.cpp:15)
==2484== Uninitialised value was created by a stack allocation
==2484== at 0x51E6ABB: (below main) (libc-start.c:137)
==2484==
==2484== Use of uninitialised value of size 8
==2484== at 0x4F4370E: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x4F43C33: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x4F501A4: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x108A85: main (arrays.cpp:15)
==2484== Uninitialised value was created by a stack allocation
==2484== at 0x51E6ABB: (below main) (libc-start.c:137)
==2484==
==2484== Conditional jump or move depends on uninitialised value(s)
==2484== at 0x4F4371B: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x4F43C33: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x4F501A4: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x108A85: main (arrays.cpp:15)
==2484== Uninitialised value was created by a stack allocation
==2484== at 0x51E6ABB: (below main) (libc-start.c:137)
==2484==
==2484== Conditional jump or move depends on uninitialised value(s)
==2484== at 0x4F43C66: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x4F501A4: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x108A85: main (arrays.cpp:15)
==2484== Uninitialised value was created by a stack allocation
==2484== at 0x51E6ABB: (below main) (libc-start.c:137)
EDIT: I changed the code. THis is the whole code i used.
compile: g++ -c -g3 arrays.cpp arrays.cpp
valgrind: valgrind --tool=memcheck --track-origins=yes --num-callers=100 --log-file=uv_log.txt ./arrays
EDIT 2:
length: 10
1 is less or equal 5
2 is less or equal 5
3 is less or equal 5
4 is less or equal 5
5 is less or equal 5
6 is greater than 5
7 is greater than 5
8 is greater than 5
9 is greater than 5
10 is greater than 5
-882498304 is less or equal 5
-188984184 is less or equal 5
1084208 is greater than 5
0 is less or equal 5
85879703 is greater than 5
0 is less or equal 5
0 is less or equal 5
You don't actually check for uninitialized access. You check for index out of bounds access. In your case, the out of bounds access is on the stack, so you access some memory, which is on the stack. And you're lucky, because the whole accessed area is on the stack, so you don't get an invalid read. Your program reads some data of the stack, which happens to be initialized for the length+1 case (because there is some other thing written to it, for example, it can be function parameter, other local variable or the function's return address), so valgrind is not able to report any error.
But for the length+10 case, it is large enough to actually read from some uninitialized memory. And I bet, if you increase 10 to a much larger number, you'll get invalid read (which causes segmentation fault).
I am trying to create Linked list in c++ using class. I used only two methods for it that is pushFront() and traverse() to push the new element in the head of the linked list and display the elements in the list at any given time. Whenever i use traverse method i am getting the error "Segmentation fault"
My code is shown below. I looked up about this error in this site and elsewhere. Segmentation fault is said to occur when we attempt to access variable which is not ours to take. i.e it is is space which is not accesible to us. But as one can see in my code I am attempting to use head and tail the private members of the class. But i am using them in the methods of the class themselves. So i should be allowed to do that right? I don't know where am i going wrong with this.
#include <iostream>
using namespace std;
struct Node
{
int data;
Node * next;
};
class LinkedList
{
private:
Node * head;
Node * tail;
public:
LinkedList();
void pushFront(int i);
void traverse();
};
LinkedList::LinkedList()
{
Node * head = NULL;
Node * tail = NULL;
}
void LinkedList::pushFront(int i)
{
Node * newNode =new Node;
newNode->data=i;
newNode->next=head;
head=newNode;
if(tail==NULL)
tail = head;
}
void LinkedList::traverse()
{
if (head==NULL){
cout<<"empty list. add elements";
return;
}
Node * ptr = head;
while(ptr!=NULL)
{
cout<<ptr->data;
ptr=ptr->next;
}
}
int main()
{
LinkedList l;
l.pushFront(10);
l.pushFront(9);
l.traverse();
return 0;
}
I expect that output should be 910 as should be printed by traverse. But i get the segmentation fault error. Can anyone point out where i am wrong?
LinkedList::LinkedList()
{
Node * head = NULL;
Node * tail = NULL;
}
must be (minimal change) :
LinkedList::LinkedList()
{
head = NULL;
tail = NULL;
}
else you do not initialize the right attributes but local variables
I encourage you to compile to produce all the warnings, if I compile your code with g++ -Wall -pedantic c.cc this gives
c.cc: In constructor 'LinkedList::LinkedList()':
c.cc:20: warning: unused variable 'head'
c.cc:21: warning: unused variable 'tail'
and this is exactly where the problem is
and about valgrind, if I execute under it that gives :
valgrind ./a.out
==18508== Memcheck, a memory error detector
==18508== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==18508== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==18508== Command: ./a.out
==18508==
==18508== Conditional jump or move depends on uninitialised value(s)
==18508== at 0x400829: LinkedList::pushFront(int) (c.cc:29)
==18508== by 0x4008C2: main (c.cc:48)
==18508==
==18508== Conditional jump or move depends on uninitialised value(s)
==18508== at 0x40089A: LinkedList::traverse() (c.cc:39)
==18508== by 0x4008DF: main (c.cc:50)
==18508==
==18508== Use of uninitialised value of size 8
==18508== at 0x400876: LinkedList::traverse() (c.cc:41)
==18508== by 0x4008DF: main (c.cc:50)
==18508==
==18508== Use of uninitialised value of size 8
==18508== at 0x400888: LinkedList::traverse() (c.cc:42)
==18508== by 0x4008DF: main (c.cc:50)
==18508==
==18508== Invalid read of size 4
==18508== at 0x400876: LinkedList::traverse() (c.cc:41)
==18508== by 0x4008DF: main (c.cc:50)
==18508== Address 0x4b43415254475542 is not stack'd, malloc'd or (recently) free'd
==18508==
==18508==
==18508== Process terminating with default action of signal 11 (SIGSEGV)
==18508== General Protection Fault
==18508== at 0x400876: LinkedList::traverse() (c.cc:41)
==18508== by 0x4008DF: main (c.cc:50)
9101778121006==18508==
==18508== HEAP SUMMARY:
==18508== in use at exit: 32 bytes in 2 blocks
==18508== total heap usage: 2 allocs, 0 frees, 32 bytes allocated
==18508==
==18508== LEAK SUMMARY:
==18508== definitely lost: 0 bytes in 0 blocks
==18508== indirectly lost: 0 bytes in 0 blocks
==18508== possibly lost: 0 bytes in 0 blocks
==18508== still reachable: 32 bytes in 2 blocks
==18508== suppressed: 0 bytes in 0 blocks
==18508== Rerun with --leak-check=full to see details of leaked memory
==18508==
==18508== For counts of detected and suppressed errors, rerun with: -v
==18508== Use --track-origins=yes to see where uninitialised values come from
==18508== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 6 from 6)
Segmentation fault
so you see also the head and tail are not initialized etc