Matrix template, memory leak - c++

I code a simple program to apply a complex function (z,exp(z),...) to a pgm image and return the result. The program is working and does what it should do. However, there are 11 memory leaks that I'm not been able to work out. My guess is that the trouble is in the matrix template container I code and its constructors and destructor.
To debug I'm using valgrind and the program has been written in c++.
The result of running valgrind is the following:
==7690== Memcheck, a memory error detector
==7690== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7690== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==7690== Command: ./tp0 -i f14.pgm -f z -o ff14.pgm
==7690==
==7690==
==7690== HEAP SUMMARY:
==7690== in use at exit: 160 bytes in 11 blocks
==7690== total heap usage: 45 allocs, 34 frees, 18,357 bytes allocated
==7690==
==7690== 8 bytes in 1 blocks are still reachable in loss record 1 of 11
==7690== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690== by 0x404871: Matrix<Pixel>::Matrix(unsigned int, unsigned int) (matrix.hpp:44)
==7690== by 0x404471: PGMImage::PGMImage(unsigned int, unsigned int) (pgm_image.cpp:14)
==7690== by 0x405475: PGMParser::set_pgm_dimensions(std::vector<int, std::allocator<int> >) (pgm_parser.cpp:147)
==7690== by 0x4050CD: PGMParser::get_pgm() (pgm_parser.cpp:94)
==7690== by 0x404D67: PGMParser::PGMParser(std::string const&) (pgm_parser.cpp:25)
==7690== by 0x404212: main (main.cpp:52)
==7690==
==7690== 8 bytes in 1 blocks are still reachable in loss record 2 of 11
==7690== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690== by 0x403703: Matrix<Complex>::Matrix(unsigned int, unsigned int) (matrix.hpp:44)
==7690== by 0x4024A5: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:49)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== 8 bytes in 1 blocks are still reachable in loss record 3 of 11
==7690== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690== by 0x4049C9: Matrix<Pixel>::Matrix(Matrix<Pixel> const&) (matrix.hpp:56)
==7690== by 0x404579: PGMImage::PGMImage(PGMImage const&) (pgm_image.cpp:31)
==7690== by 0x4024DD: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:57)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== 12 bytes in 1 blocks are still reachable in loss record 4 of 11
==7690== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690== by 0x4048B4: Matrix<Pixel>::Matrix(unsigned int, unsigned int) (matrix.hpp:46)
==7690== by 0x404471: PGMImage::PGMImage(unsigned int, unsigned int) (pgm_image.cpp:14)
==7690== by 0x405475: PGMParser::set_pgm_dimensions(std::vector<int, std::allocator<int> >) (pgm_parser.cpp:147)
==7690== by 0x4050CD: PGMParser::get_pgm() (pgm_parser.cpp:94)
==7690== by 0x404D67: PGMParser::PGMParser(std::string const&) (pgm_parser.cpp:25)
==7690== by 0x404212: main (main.cpp:52)
==7690==
==7690== 12 bytes in 1 blocks are still reachable in loss record 5 of 11
==7690== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690== by 0x404A15: Matrix<Pixel>::Matrix(Matrix<Pixel> const&) (matrix.hpp:59)
==7690== by 0x404579: PGMImage::PGMImage(PGMImage const&) (pgm_image.cpp:31)
==7690== by 0x4024DD: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:57)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== 16 bytes in 1 blocks are still reachable in loss record 6 of 11
==7690== at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690== by 0x40445E: PGMImage::PGMImage(unsigned int, unsigned int) (pgm_image.cpp:14)
==7690== by 0x405475: PGMParser::set_pgm_dimensions(std::vector<int, std::allocator<int> >) (pgm_parser.cpp:147)
==7690== by 0x4050CD: PGMParser::get_pgm() (pgm_parser.cpp:94)
==7690== by 0x404D67: PGMParser::PGMParser(std::string const&) (pgm_parser.cpp:25)
==7690== by 0x404212: main (main.cpp:52)
==7690==
==7690== 16 bytes in 1 blocks are still reachable in loss record 7 of 11
==7690== at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690== by 0x40248A: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:49)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== 16 bytes in 1 blocks are still reachable in loss record 8 of 11
==7690== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690== by 0x403740: Matrix<Complex>::Matrix(unsigned int, unsigned int) (matrix.hpp:46)
==7690== by 0x4024A5: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:49)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== 16 bytes in 1 blocks are still reachable in loss record 9 of 11
==7690== at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690== by 0x404564: PGMImage::PGMImage(PGMImage const&) (pgm_image.cpp:31)
==7690== by 0x4024DD: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:57)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== 24 bytes in 1 blocks are still reachable in loss record 10 of 11
==7690== at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690== by 0x405464: PGMParser::set_pgm_dimensions(std::vector<int, std::allocator<int> >) (pgm_parser.cpp:147)
==7690== by 0x4050CD: PGMParser::get_pgm() (pgm_parser.cpp:94)
==7690== by 0x404D67: PGMParser::PGMParser(std::string const&) (pgm_parser.cpp:25)
==7690== by 0x404212: main (main.cpp:52)
==7690==
==7690== 24 bytes in 1 blocks are still reachable in loss record 11 of 11
==7690== at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690== by 0x4024CB: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:57)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== LEAK SUMMARY:
==7690== definitely lost: 0 bytes in 0 blocks
==7690== indirectly lost: 0 bytes in 0 blocks
==7690== possibly lost: 0 bytes in 0 blocks
==7690== still reachable: 160 bytes in 11 blocks
==7690== suppressed: 0 bytes in 0 blocks
==7690==
==7690== For counts of detected and suppressed errors, rerun with: -v
==7690== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
The part of code I think is crashing of matrix template is the following:
template<typename T>
class Matrix
{
private:
T** matrix_;
unsigned int rows_;
unsigned int cols_;
public:
Matrix();
Matrix(unsigned int, unsigned int);
Matrix(Matrix const &);
~Matrix();
Matrix const &operator=(Matrix const &);
//more methods...
};
template<typename T>
Matrix<T>::Matrix()
: matrix_(0), rows_(0), cols_(0) {}
template<typename T>
Matrix<T>::Matrix(unsigned int rows, unsigned int cols)
{
matrix_ = new T*[rows];
for(unsigned int i=0; i < rows; i++)
matrix_[i] = new T[cols];
rows_ = rows;
cols_ = cols;
}
template<typename T>
Matrix<T>::Matrix(Matrix<T> const & m_orig)
{
rows_ = m_orig.rows_;
cols_ = m_orig.cols_;
matrix_ = new T*[rows_];
for(unsigned int i=0; i < rows_; i++)
{
matrix_[i] = new T[cols_];
for(unsigned int j=0; j < cols_; j++)
matrix_[i][j]=m_orig.matrix_[i][j];
}
}
template<typename T>
Matrix<T>::~Matrix()
{
for(unsigned int i=0; i < rows_; i++)
delete matrix_[i];
delete []matrix_;
rows_ = 0;
cols_ = 0;
}
template<typename T>
Matrix<T> const & Matrix<T>::operator=(Matrix const & m_orig)
{
if(this != &m_orig)
{
for(unsigned int k=0; k < rows_; k++)
delete matrix_[k];
delete matrix_;
rows_ = m_orig.rows_;
cols_ = m_orig.cols_;
matrix_ = new T*[rows_];
for(unsigned int i=0; i < rows_; i++)
{
matrix_[i] = new T[cols_];
for(unsigned int j=0; j < cols_; j++)
matrix_[i][j]=m_orig.matrix_[i][j];
}
}
return *this;
}
There are other classes that could fail, but valgrind tracks almost every leak to the matrix container.
Your help is greatly appreciated!

You should follow the same "pattern" for deallocation with delete as you do for allocation with new,
for(unsigned int i=0; i < rows_; i++)
delete [] matrix_[i];
// ~~ notice []
delete []matrix_;

Your assignment operator is not exception-safe and fails to use the correct version of delete: it releases the memory using delete matrix_ rather than delete[] matrix_. Given the current implementation you are much better off replacing it by this version:
template <typename T>
Matrix<T> const& Matrix<T>::operator= (Matrix<T> orig) {
this->swap(orig);
return *this;
}
template <typename T>
void Matrix<T>::swap(Matrix<T>& other) {
using std::swap;
swap(this->matrix_, other.matrix_);
}
Aside from fixing the memory issues noted above, it also makes the implementation strong exception safe. Of course, doing so assumes that the copy constructor, destructor, and swap() are correctly implemented as they are leveraged to implement this assignment operator:
A copy of the original is made to create the argument (which may be elided: since a copy is made anyway taking the argument by value rather than be const& can reduce the number of copies).
The argument the left hand side are exchanged, making the left hand side the same as the original argument while the argument now contain the original left hand side state ready to be released.
The argument is destroyed, releasing the original left hand side state.
The destructor is also incorrect: it uses delete matrix_[k] instead of delete[] matrix_[k]. Conventionally objects are destroyed in the opposite order of construction while your code destroys objects in the opposite order. I'd recommend using std::vector<std::vector<T>> to maintain the data inside the Matrix<T>, too.

Related

valgrind shows memory leak in vector constructor

I am writing a compiler using bison and C++, and I just checked memory leak with Valgrind. While it shows there's memory leak caused by vector constructor shown below:
==6562== HEAP SUMMARY:
==6562== in use at exit: 90,298 bytes in 27 blocks
==6562== total heap usage: 125 allocs, 98 frees, 100,782 bytes allocated
==6562==
==6562== 80 (32 direct, 48 indirect) bytes in 1 blocks are definitely lost in loss record 19 of 22
==6562== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6562== by 0x40DB9B: __gnu_cxx::new_allocator<std::shared_ptr<Node> >::allocate(unsigned long, void const*) (new_allocator.h:104)
==6562== by 0x40D3B9: std::allocator_traits<std::allocator<std::shared_ptr<Node> > >::allocate(std::allocator<std::shared_ptr<Node> >&, unsigned long) (alloc_traits.h:491)
==6562== by 0x40C465: std::_Vector_base<std::shared_ptr<Node>, std::allocator<std::shared_ptr<Node> > >::_M_allocate(unsigned long) (stl_vector.h:170)
==6562== by 0x41C170: std::_Vector_base<std::shared_ptr<Node>, std::allocator<std::shared_ptr<Node> > >::_M_create_storage(unsigned long) (stl_vector.h:185)
==6562== by 0x41ADB6: std::_Vector_base<std::shared_ptr<Node>, std::allocator<std::shared_ptr<Node> > >::_Vector_base(unsigned long, std::allocator<std::shared_ptr<Node> > const&) (stl_vector.h:136)
==6562== by 0x41A13F: std::vector<std::shared_ptr<Node>, std::allocator<std::shared_ptr<Node> > >::vector(std::vector<std::shared_ptr<Node>, std::allocator<std::shared_ptr<Node> > > const&) (stl_vector.h:320)
==6562== by 0x417ECF: OprNode::OprNode(int, std::vector<std::shared_ptr<Node>, std::allocator<std::shared_ptr<Node> > > const&) (Node.cpp:52)
==6562== by 0x406C7B: opr(int, std::vector<Node*, std::allocator<Node*> > const&) (parser.y:175)
==6562== by 0x40555B: yyparse() (parser.y:125)
==6562== by 0x40748B: main (parser.y:253)
==6562==
==6562== LEAK SUMMARY:
==6562== definitely lost: 32 bytes in 1 blocks
==6562== indirectly lost: 48 bytes in 2 blocks
==6562== possibly lost: 0 bytes in 0 blocks
==6562== still reachable: 90,218 bytes in 24 blocks
==6562== suppressed: 0 bytes in 0 blocks
==6562== Reachable blocks (those to which a pointer was found) are not shown.
==6562== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==6562==
==6562== For counts of detected and suppressed errors, rerun with: -v
==6562== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Relevant code:
class Node {
public:
Node()=default;
virtual void ex(int, int, int) const = 0;
virtual void check(vector<int>&, int) const = 0;
};
class OprNode:public Node {
public:
OprNode(int, const vector<shared_ptr<Node>>&);
void ex(int, int, int) const;
void check(vector<int>&, int) const;
private:
int oper;
vector<shared_ptr<Node>> op;
};
OprNode::OprNode(int oper, const vector<shared_ptr<Node> >& op):oper(oper), op(op) {;}
Node * opr(int oper, const vector<Node *>& op) {
auto v = vector<shared_ptr<Node> >();
for (const auto i: op) {
v.push_back(shared_ptr<Node>(i));
}
return new OprNode(oper, v);
}
Due to the limitation of bison, I must use raw pointer as the return type and content of vector passed into opr.
Thanks a lot!

valgrind detects errors when c++ exception is not caught

I notice that the valgrind reports possible memory leak for the following minimal example:
#include <stdexcept>
int main() {
try {
throw std::logic_error("test");
}
catch (std::exception& e) {
std::string msg("test2 ");
msg.append(e.what());
throw std::logic_error(msg);
}
return 0;
}
After compiling it with g++ test.cpp -g, the valgrind detects some errors with valgrind --tool=memcheck --leak-check=full ./a.out. Is this normal?
I concern this issue because the valgrind reports some errors of my R extensions which is similar to this example.
The valgrind version is: 3.10.0.SVN. The gcc version is 4.8.2 (Ubuntu 4.8.2-19ubuntu1). The reported message is shown below:
==8640== Memcheck, a memory error detector
==8640== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==8640== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==8640== Command: ./a.out
==8640==
terminate called after throwing an instance of 'std::logic_error'
what(): test2 test
==8640==
==8640== HEAP SUMMARY:
==8640== in use at exit: 354 bytes in 4 blocks
==8640== total heap usage: 6 allocs, 2 frees, 417 bytes allocated
==8640==
==8640== 29 bytes in 1 blocks are possibly lost in loss record 1 of 4
==8640== at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8640== by 0x4EF13B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x4EF2AE0: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x4EF2EF7: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x400BA7: main (test.cpp:4)
==8640==
==8640== 37 bytes in 1 blocks are possibly lost in loss record 2 of 4
==8640== at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8640== by 0x4EF13B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x4EF1F7A: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x4EF2013: std::string::reserve(unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x4EF225E: std::string::append(char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x400CC6: main (test.cpp:8)
==8640==
==8640== 144 bytes in 1 blocks are possibly lost in loss record 3 of 4
==8640== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8640== by 0x4E944E2: __cxa_allocate_exception (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x400B83: main (test.cpp:4)
==8640==
==8640== 144 bytes in 1 blocks are possibly lost in loss record 4 of 4
==8640== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8640== by 0x4E944E2: __cxa_allocate_exception (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x400CD0: main (in /home/wush/Test/a.out)
==8640==
==8640== LEAK SUMMARY:
==8640== definitely lost: 0 bytes in 0 blocks
==8640== indirectly lost: 0 bytes in 0 blocks
==8640== possibly lost: 354 bytes in 4 blocks
==8640== still reachable: 0 bytes in 0 blocks
==8640== suppressed: 0 bytes in 0 blocks
==8640==
==8640== For counts of detected and suppressed errors, rerun with: -v
==8640== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 1 from 1)
Aborted (core dumped)

Memory Corruption on Allocation

I've been having a problem with allocating memory for one of my data structures. It always crashes out, but it's not always at the same place. My suspicion is that I'm trying to allocate it over the top of something that's already there, but I'm really not sure how to tell what's actually going on or how to fix it - I've tried to install valgrind, but that doesn't yet support Mac OS 10.10.
This is the code that calls the function.
stet::file f1;
f1.set_path("test/longfile1.txt"); // a file with almost 2 million lines
f1.read();
std::string all_text = f1.get_contents();
std::vector<chunk *> chunks = populate_chunks(all_text);
These are my data structures - the idea is that the text from file is split into fixed sized chunks, which are populated up to 75% capacity, but I can't seem to create all the chunks.
struct line {
std::string text;
};
struct chunk {
line *lines[MAX_CHUNK_SIZE];
};
And this is the cause of my nightmares - it crashes out on the line below all the comments.
std::vector<chunk *> populate_chunks(std::string &text) {
std::vector<std::string> all_lines;
boost::split(all_lines, text, boost::is_any_of("\n"));
size_t num_lines = all_lines.size();
std::vector<chunk *> chunks = std::vector<chunk *>( (num_lines / START_CHUNK_SIZE) * 2 );
size_t next_line_num;
for(size_t line_num = 0; line_num < num_lines; line_num = next_line_num) {
next_line_num = line_num + START_CHUNK_SIZE;
std::cout << line_num << std::endl;
chunk *c = new chunk;
chunks.push_back(c);
// This always falls over, but not always at the same point in the file.
// Never seems to be the first time. Observed range: 3072 - 59904
// Error always looks something like this:
// text(71184,0x7fff77699300) malloc: *** error for object 0x7ff389006208: incorrect checksum for freed object - object was probably modified after being freed.
// *** set a breakpoint in malloc_error_break to debug
for(size_t i = 0; i < next_line_num; ++i) {
line *l = new line;
l->text = all_lines[line_num+i];
c->lines[i] = l;
}
}
return chunks;
}
If anyone has any ideas, they'd be much appreciated - it should be noted that I'm pretty new to C++, so it's quite likely that I've missed something really stupid.
Update:
I've fiddled around with the code to change things based on the comments I've been getting:
Made chunks the function's return value, rather than a pointer
Stopped giving the all_lines vector a size on creation, allowed boost to sort that out
I also got a fedora VM up and running in order to put it through valgrind and I'm really very confused by the output.
Noted the values of MAX_CHUNK_SIZE and START_CHUNK_SIZE below.
Macro values:
#define MAX_CHUNK_SIZE 1024
#define START_CHUNK_SIZE MAX_CHUNK_SIZE * 0.75
Valgrind output after the above changes:
==24468== Memcheck, a memory error detector
==24468== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==24468== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==24468== Command: bin/text
==24468==
==24468== Invalid write of size 8
==24468== at 0x402907: populate_chunks(std::string&) (text_storage.cc:125)
==24468== by 0x402ADF: main (text_storage.cc:173)
==24468== Address 0x216b5640 is 0 bytes after a block of size 8,192 alloc'd
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x402888: populate_chunks(std::string&) (text_storage.cc:113)
==24468== by 0x402ADF: main (text_storage.cc:173)
==24468==
==24468==
==24468== Process terminating with default action of signal 11 (SIGSEGV)
==24468== Access not within mapped region at address 0x37D77000
==24468== at 0x402907: populate_chunks(std::string&) (text_storage.cc:125)
==24468== by 0x402ADF: main (text_storage.cc:173)
==24468== If you believe this happened as a result of a stack
==24468== overflow in your program's main thread (unlikely but
==24468== possible), you can try to increase the size of the
==24468== main thread stack using the --main-stacksize= flag.
==24468== The main thread stack size used in this run was 8388608.
==24468==
==24468== HEAP SUMMARY:
==24468== in use at exit: 371,641,698 bytes in 6,241,143 blocks
==24468== total heap usage: 6,241,190 allocs, 47 frees, 656,880,685 bytes allocated
==24468==
==24468== 16 bytes in 2 blocks are possibly lost in loss record 1 of 11
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x4028BC: populate_chunks(std::string&) (text_storage.cc:123)
==24468== by 0x402ADF: main (text_storage.cc:173)
==24468==
==24468== 43 bytes in 1 blocks are possibly lost in loss record 2 of 11
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x5340048: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x5341900: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x5341D37: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x4029F7: main (text_storage.cc:138)
==24468==
==24468== 35,727,800 (33,173,592 direct, 2,554,208 indirect) bytes in 4,146,699 blocks are definitely lost in loss record 8 of 11
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x4028BC: populate_chunks(std::string&) (text_storage.cc:123)
==24468== by 0x402ADF: main (text_storage.cc:173)
==24468==
==24468== 93,350,023 bytes in 1 blocks are possibly lost in loss record 9 of 11
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x5340048: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x5340235: std::string::_M_mutate(unsigned long, unsigned long, unsigned long) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x53403C5: std::string::_M_leak_hard() (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x5340412: std::string::begin() (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x407728: boost::range_iterator<std::string>::type boost::range_detail::range_begin<std::string>(std::string&) (begin.hpp:49)
==24468== by 0x40705D: boost::range_iterator<std::string>::type boost::range_adl_barrier::begin<std::string>(std::string&) (begin.hpp:108)
==24468== by 0x4066FC: __gnu_cxx::__normal_iterator<char*, std::string> boost::iterator_range_detail::iterator_range_impl<__gnu_cxx::__normal_iterator<char*, std::string> >::adl_begin<std::string>(std::string&) (iterator_range_core.hpp:58)
==24468== by 0x40601A: boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::string> >::iterator_range<std::string>(std::string&, boost::iterator_range_detail::range_tag) (iterator_range_core.hpp:207)
==24468== by 0x40561F: boost::iterator_range<boost::range_iterator<std::string>::type> boost::make_iterator_range<std::string>(std::string&) (iterator_range_core.hpp:559)
==24468== by 0x404BC3: boost::iterator_range<boost::range_iterator<std::string>::type> boost::range_detail::make_range<std::string>(std::string&, long) (as_literal.hpp:93)
==24468== by 0x4040E5: boost::iterator_range<boost::range_iterator<std::string>::type> boost::as_literal<std::string>(std::string&) (as_literal.hpp:102)
==24468==
==24468== 93,351,904 bytes in 1 blocks are possibly lost in loss record 10 of 11
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x5340048: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x5341710: char* std::string::_S_construct<char*>(char*, char*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x531F9A7: std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::str() const (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x402523: stet::file::read() (file.cc:50)
==24468== by 0x402A2E: main (text_storage.cc:139)
==24468==
==24468== 129,441,960 bytes in 1,520,226 blocks are possibly lost in loss record 11 of 11
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x5340048: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x40845E: char* std::string::_S_construct<__gnu_cxx::__normal_iterator<char*, std::string> >(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, std::allocator<char> const&, std::forward_iterator_tag) (basic_string.tcc:138)
==24468== by 0x4082E8: char* std::string::_S_construct_aux<__gnu_cxx::__normal_iterator<char*, std::string> >(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, std::allocator<char> const&, std::__false_type) (basic_string.h:1725)
==24468== by 0x408177: char* std::string::_S_construct<__gnu_cxx::__normal_iterator<char*, std::string> >(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, std::allocator<char> const&) (basic_string.h:1746)
==24468== by 0x407FDA: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<__gnu_cxx::__normal_iterator<char*, std::string> >(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, std::allocator<char> const&) (basic_string.tcc:229)
==24468== by 0x407D6A: std::string boost::copy_range<std::string, boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::string> > >(boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::string> > const&) (iterator_range_core.hpp:643)
==24468== by 0x407AEA: boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >::operator()(boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::string> > const&) const (util.hpp:97)
==24468== by 0x407395: boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default>::dereference() const (transform_iterator.hpp:121)
==24468== by 0x406B72: boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default>::reference boost::iterator_core_access::dereference<boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default> >(boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default> const&) (iterator_facade.hpp:514)
==24468== by 0x40633D: boost::iterator_facade<boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default>, std::string, boost::forward_traversal_tag, std::string, long>::operator*() const (iterator_facade.hpp:639)
==24468== by 0x405895: void std::vector<std::string, std::allocator<std::string> >::_M_range_initialize<boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default> >(boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default>, boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default>, std::input_iterator_tag) (stl_vector.h:1188)
==24468==
==24468== LEAK SUMMARY:
==24468== definitely lost: 33,173,592 bytes in 4,146,699 blocks
==24468== indirectly lost: 2,554,208 bytes in 319,276 blocks
==24468== possibly lost: 316,143,946 bytes in 1,520,231 blocks
==24468== still reachable: 19,769,952 bytes in 254,937 blocks
==24468== suppressed: 0 bytes in 0 blocks
==24468== Reachable blocks (those to which a pointer was found) are not shown.
==24468== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==24468==
==24468== For counts of detected and suppressed errors, rerun with: -v
==24468== ERROR SUMMARY: 4146708 errors from 7 contexts (suppressed: 2 from 2)
The size of the lines array in a chunk is MAX_CHUNK_SIZE, but you are accessing it far beyond that on any iteration except the first.
Your loop is for(size_t i = 0; i < next_line_num; ++i), guess what next_line_num is on your second (and beyond) iteration?
You would probably have totally avoided this problem if you had thought of another problem, which you overlooked. You only partially fill the chunks (by 75%), which makes sense. But on the last iteration you are likely to have even less lines than those needed to fill 75% of a chunk. Therefore there should be, somewhere, a test to handle this boundary. A comparison, somewhere in that loop, with num_lines. Thinking about where to put it could (but not necessarily would) have alerted you that the iteration index is not doing what you expect.
Try for(size_t i = 0; i < START_CHUNK_SIZE && line_num+i < num_lines; ++i).
For reference, this is what the final code looks like:
std::vector<chunk *> populate_chunks(std::string &text) {
std::vector<std::string> all_lines;
boost::split(all_lines, text, boost::is_any_of("\n"));
size_t num_lines = all_lines.size();
std::vector<chunk *> chunks = std::vector<chunk *>( (num_lines / START_CHUNK_SIZE) * 2 );
for(size_t next_line_num, line_num = 0; line_num < num_lines; line_num = next_line_num) {
next_line_num = line_num + START_CHUNK_SIZE;
chunk *c = new chunk;
chunks.push_back(c);
for(size_t i = 0; i < std::min(static_cast<unsigned int>(START_CHUNK_SIZE), static_cast<unsigned int>(num_lines - line_num) ); ++i) {
line *l = new line;
l->text = all_lines[line_num+i];
c->lines[i] = l;
}
}
return chunks;
}

Valgrind identifies memory leaks when using string-type member (compiling with nvcc)

I'm not sure if it's a bug or not, but when I use string-type members inside structures or classes, valgrind identifies memory leaks. I've tried to build a simple code based on my own application, I'm sorry if it is still big...
// ====================================================================
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
// ====================================================================
string int2str(const int &i) {
return static_cast<ostringstream*>(
&(ostringstream() << i))->str();
}
// ====================================================================
class P;
// ====================================================================
struct Node {
virtual char isType() const = 0;
};
// ====================================================================
struct X : Node {
string st;
int id;
X(const string &_st, const int &_id);
char isType() const { return 'x'; };
// Those member functions are after class P declaration:
P use_as_P();
P use_as_P(const P &arg0);
P use_as_P(const P &arg0, const P &arg1);
};
X::X(const string &_st, const int &_id) : st(_st), id(_id) { }
// ====================================================================
class P {
friend struct X;
private:
Node *node;
vector<P> children;
public:
P() : node(NULL) {};
P(const P &source);
void swap(P &other);
string print_this();
~P();
};
P::P(const P &source) {
this->children = source.children;
switch(source.node->isType()) {
case 'x':
this->node = new X(static_cast<X*>(source.node)->st,
static_cast<X*>(source.node)->id);
break;
}
}
void P::swap(P &other) {
std::swap(this->node, other.node);
std::swap(this->children, other.children);
}
string P::print_this() {
string msg = "( ";
msg += static_cast<X*>(this->node)->st;
msg += int2str(static_cast<X*>(this->node)->id);
msg += " ";
for(size_t i = 0; i < this->children.size(); i++)
msg += children.at(i).print_this();
msg += ") ";
return msg;
}
P::~P() {
if(this->node != NULL)
delete node;
this->children.clear();
}
// ====================================================================
P X::use_as_P() {
P ast_aux;
ast_aux.node = new X(this->st,this->id);
return ast_aux;
}
P X::use_as_P(const P &arg0) {
P ast_aux;
ast_aux.node = new X(this->st,this->id);
ast_aux.children.push_back(arg0);
return ast_aux;
}
P X::use_as_P(const P &arg0, const P &arg1) {
P ast_aux;
ast_aux.node = new X(this->st,this->id);
ast_aux.children.push_back(arg0);
ast_aux.children.push_back(arg1);
return ast_aux;
}
// ====================================================================
// ** MAIN **
// ====================================================================
int main(int argc, char **argv)
{
X a("how",0), b("what",1), c("why",2), d("when",3);
P testing = a.use_as_P(b.use_as_P(c.use_as_P()),d.use_as_P());
cout << testing.print_this() << endl;
return 0;
}
// ====================================================================
Compiling with:
nvcc -arch sm_20 -o LEAK_test_with_string LEAK_test_with_string.cu
And here goes the valgrind's analysis:
==5877== Memcheck, a memory error detector
==5877== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==5877== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==5877== Command: ./LEAK_test_with_string
==5877==
( how0 ( what1 ( why2 ) ) ( when3 ) )
==5877==
==5877== HEAP SUMMARY:
==5877== in use at exit: 114 bytes in 4 blocks
==5877== total heap usage: 47 allocs, 43 frees, 3,701 bytes allocated
==5877==
==5877== 28 bytes in 1 blocks are definitely lost in loss record 1 of 4
==5877== at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5877== by 0x5516F38: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518640: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518A57: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x403691: main (in /home/igor/projects/system_modeling/LEAK_test_with_string)
==5877== : st(_st), id(_id) {}
==5877== 28 bytes in 1 blocks are definitely lost in loss record 2 of 4
==5877== at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5877== by 0x5516F38: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518640: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518A57: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x40375A: main (in /home/igor/projects/system_modeling/LEAK_test_with_string)
==5877==
==5877== 29 bytes in 1 blocks are definitely lost in loss record 3 of 4
==5877== at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5877== by 0x5516F38: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518640: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518A57: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x4036F7: main (in /home/igor/projects/system_modeling/LEAK_test_with_string)
==5877==
==5877== 29 bytes in 1 blocks are definitely lost in loss record 4 of 4
==5877== at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5877== by 0x5516F38: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518640: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518A57: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x4037BD: main (in /home/igor/projects/system_modeling/LEAK_test_with_string)
==5877==
==5877== LEAK SUMMARY:
==5877== definitely lost: 114 bytes in 4 blocks
==5877== indirectly lost: 0 bytes in 0 blocks
==5877== possibly lost: 0 bytes in 0 blocks
==5877== still reachable: 0 bytes in 0 blocks
==5877== suppressed: 0 bytes in 0 blocks
==5877==
==5877== For counts of detected and suppressed errors, rerun with: -v
==5877== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 2 from 2)
The "it's a bug" wondering comes when I change the C++ string member into a plain C char* member. One just need to change this part of the above written code:
// ====================================================================
struct X : Node {
char st[6]; // <=============== HERE!
int id;
X(const string &_st, const int &_id);
char isType() const { return 'x'; };
// Those member functions are after class P declaration:
P use_as_P();
P use_as_P(const P &arg0);
P use_as_P(const P &arg0, const P &arg1);
};
X::X(const string &_st, const int &_id) : id(_id) { // <=============== HERE!
strcpy(st, _st.c_str()); // <=============== HERE!
}
// ====================================================================
Note that I still use string in my code, but now there isn't any string member declared. This way, valgrind doesn't complain anymore:
==5977== Memcheck, a memory error detector
==5977== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==5977== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==5977== Command: ./LEAK_test_without_string
==5977==
( how0 ( what1 ( why2 ) ) ( when3 ) )
==5977==
==5977== HEAP SUMMARY:
==5977== in use at exit: 0 bytes in 0 blocks
==5977== total heap usage: 57 allocs, 57 frees, 3,986 bytes allocated
==5977==
==5977== All heap blocks were freed -- no leaks are possible
==5977==
==5977== For counts of detected and suppressed errors, rerun with: -v
==5977== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Does anybody have an insight on this? I mean, is this a bug that should be reported or is there something that I'm actually missing in my string-version code?
Since no one's bitten the bullet I'll expand my comment: Your Node class does not have a virtual destructor, this makes the following line
delete node;
invoke undefined behaviour - this will only call the destructor for Node, the destructor for X is never called.
The solution is simple, provide a virtual destructor for Node:
struct Node {
virtual char isType() const = 0;
virtual ~Node() =default;
// or virtual ~Node(){} if your compiler does not support defaulted functions.
}
You can now safely delete base pointers of Node that point to inherited classes.
The reason for the memory leak when using a std::string is because when you delete the base pointer node, the destructor for X is not called, and so neither is the destructor for st. The char array version doesn't leak because node points to a simple block of memory, and X in this case doesn't have any complex members that require destruction, so delete node luckily releases all of the memory allocated for X and its members. Remember that this is undefined behaviour however and the compiler can legitimately do whatever it wants to.
If you have a base class with even a single virtual function, always add a virtual destructor. You can make a case for omitting a virtual destructor if you are absolutely sure you won't be deleting inherited classes using a pointer to the base class, but it's safer to just add one anyway just in case (the gcc compiler flag -Weffc++ will also tell you as much).

Valgrind error with std::cin

Here is my code:
std::string getword()
{
std::string temp;
std::cin >> temp;
return temp;
}
Valgrind throws an error on the line std::cin >> temp.
Here is the valgrind output for those who asked:
HEAP SUMMARY:
==18490== in use at exit: 33 bytes in 1 blocks
==18490== total heap usage: 397 allocs, 396 frees, 12,986 bytes allocated
==18490==
==18490== 33 bytes in 1 blocks are possibly lost in loss record 1 of 1
==18490== at 0x4C2AF8E: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18490== by 0x4EEE3B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==18490== by 0x4EEF127: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==18490== by 0x4EEF20F: std::string::reserve(unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==18490== by 0x4EA7D14: std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==18490== by 0x401681: getword() (netsim.cc:29)
==18490== by 0x401F6E: main (netsim.cc:96)
==18490==
==18490== LEAK SUMMARY:
==18490== definitely lost: 0 bytes in 0 blocks
==18490== indirectly lost: 0 bytes in 0 blocks
==18490== possibly lost: 33 bytes in 1 blocks
==18490== still reachable: 0 bytes in 0 blocks
==18490== suppressed: 0 bytes in 0 blocks
==18490==
==18490== For counts of detected and suppressed errors, rerun with: -v
==18490== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)
netsim.cc:96 is the second call to getword() in the program. That code reads
std::string network = getword();
netsim.cc:29 is the code for getword() itself. Line 29 is the line
std::cin >> temp
I still don't understand why this happened but I managed to resolve the issue.
I had the code
std::string s = getword();
immediatly above
std::string network = getword();
I made both s and network global variables and somehow the issue was resolved.
If anyone can explain why that is though I would be grateful.
I'm not a valgrind Expert, but I'm tentative to say that this is a false positive. In fact, it might even be a false positive generated by valgrind itself. Looking at the Leak Summary and seeing the core origin of the leak, I get suspicious:
// The one right below this, that's at the top of that valgrind error
==18490== at 0x4C2AF8E: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18490== by 0x4EEE3B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
Now why would valgrind be reporting a memory leak from its own shared library ? Something doesn't seem right here. Either valgrind itself isn't very clean in how its allocating that memory (and valgrind has its own leak! Oh noes!) or it's throwing a really strange false positive. Unless the newest branches of GCC have produced a memory leak for std::string and the istream& operator<< recently, I can't imagine this actually leaking. std::cin and std::cout have been being used for ages, and it makes no sense that valgrind would toss an error over it, especially when your client code isn't making a single new/delete call.
So, in short, there's a few things that could be happening here:
valgrind is leaking. (Maybe? It's originating from a valgrind function)
GCC is leaking? (Hesitant to say this)
valgrind is drunk! :[
In either case, ignore it and move on. I doubt this is going to shatter your netsim in any crucial way.
I hope it clears up soon, and I'm sorry my answer can only say this much, but these are the best shots I can give.