Structure with same name, different definitions: segmentation fault with -O2 - c++

I've encountered a segmentation fault in a C++ program when two C++ files compiled together each include a different definition of a structure (with the same name).
According to this question, I understand that structure definitions are restricted to the translation unit (the file and its inclusions).
However, I get a crash when enabling -O1 or more at compile time.
The following minimal code reproduced the segfault.
The code is in 3 short C++ files and 2 headers:
// td_collision1.cc
#include <iostream>
#include <vector>
#include <cstdlib>
#include "td1.h"
struct Data
{
long a;
double m1;
double m2;
};
void sz1(void) {
std::cout << "Size of in collision1: " << sizeof(struct Data) << std::endl;
}
void collision1(void) {
struct Data tmp;
std::vector<struct Data> foo;
for (int i=0; i<10; i++) {
tmp.a = 1;
tmp.m1 = 0;
tmp.m2 = 0;
foo.push_back(tmp);
}
}
// td1.h
#include <iostream>
void collision1(void);
void sz1(void);
// td_collision2.cc
#include <iostream>
#include <vector>
#include <cstdlib>
#include "td2.h"
struct Data {
long a;
double m1; // note that there is one member less here
};
void sz2(void) {
std::cout << "Size of in collision2: " << sizeof(struct Data) << std::endl;
}
void collision2(void) {
struct Data tmp2;
std::vector<struct Data> bar;
for (int i=0; i<100; i++) {
tmp2.a = 1;
tmp2.m1 = 0;
bar.push_back(tmp2); // errors occur here
}
}
// td2.h
#include <iostream>
void collision2(void);
void sz2(void);
// td_main.cc
#include <iostream>
#include <cstdlib>
#include "td1.h"
#include "td2.h"
int main(void) {
sz1();
sz2();
collision2();
}
This code compiled with GCC 6.3 with -O0 flag runs fine and without error under valgrind.
However, running it with -O1 or O2 leads to the following output:
Size of in collision1: 24
Size of in collision2: 16
==326== Invalid write of size 8
==326== at 0x400F6C: construct<Data, const Data&> (new_allocator.h:120)
==326== by 0x400F6C: construct<Data, const Data&> (alloc_traits.h:455)
==326== by 0x400F6C: push_back (stl_vector.h:918)
==326== by 0x400F6C: collision2() (td_collision2.cc:22)
==326== by 0x400FE8: main (td_main.cc:10)
==326== Address 0x5aba1f0 is 0 bytes after a block of size 96 alloc'd
==326== at 0x4C2E1FC: operator new(unsigned long) (vg_replace_malloc.c:334)
==326== by 0x400DE9: allocate (new_allocator.h:104)
==326== by 0x400DE9: allocate (alloc_traits.h:416)
==326== by 0x400DE9: _M_allocate (stl_vector.h:170)
==326== by 0x400DE9: void std::vector<Data, std::allocator<Data> >::_M_emplace_back_aux<Data const&>(Data const&) (vector.tcc:412)
==326== by 0x400F7E: push_back (stl_vector.h:924)
==326== by 0x400F7E: collision2() (td_collision2.cc:22)
==326== by 0x400FE8: main (td_main.cc:10)
==326==
==326== Invalid write of size 8
==326== at 0x400F69: construct<Data, const Data&> (new_allocator.h:120)
==326== by 0x400F69: construct<Data, const Data&> (alloc_traits.h:455)
==326== by 0x400F69: push_back (stl_vector.h:918)
==326== by 0x400F69: collision2() (td_collision2.cc:22)
==326== by 0x400FE8: main (td_main.cc:10)
==326== Address 0x5aba1f8 is 8 bytes after a block of size 96 alloc'd
==326== at 0x4C2E1FC: operator new(unsigned long) (vg_replace_malloc.c:334)
==326== by 0x400DE9: allocate (new_allocator.h:104)
==326== by 0x400DE9: allocate (alloc_traits.h:416)
==326== by 0x400DE9: _M_allocate (stl_vector.h:170)
==326== by 0x400DE9: void std::vector<Data, std::allocator<Data> >::_M_emplace_back_aux<Data const&>(Data const&) (vector.tcc:412)
==326== by 0x400F7E: push_back (stl_vector.h:924)
==326== by 0x400F7E: collision2() (td_collision2.cc:22)
==326== by 0x400FE8: main (td_main.cc:10)
==326==
==326==
==326== HEAP SUMMARY:
==326== in use at exit: 0 bytes in 0 blocks
==326== total heap usage: 5 allocs, 5 frees, 73,896 bytes allocated
==326==
==326== All heap blocks were freed -- no leaks are possible
==326==
==326== For counts of detected and suppressed errors, rerun with: -v
==326== ERROR SUMMARY: 191 errors from 2 contexts (suppressed: 0 from 0)
the push_back() function fails when the libc reallocates std::vector<struct Data> bar. (in my case, its size is 4 items initially, and the vector is further resized afterwards when calling push_back() in the loop.)
When struct Data in td_collision1.cc has the same size as in td_collision2.cc, the program doesn't crash.
Therefore, there seem to be a collision between these two structure definitions. Indeed, if I rename one structure, the bug obviously vanishes.
But, as mentioned above, I thought that this could not happen. What did I misunderstood?
Also, if I get rid of function collision1(), the segfault vanishes (struct Data in collision1 is probably ditched by the compiler because unused)
My understanding was that there exist a clear separation between these two CC files and no "crosstalk" should be possible if the structures are not present in the header.
Edit: add missing td2.h

The answer you linked is for C language, and C is not C++.
In C++ (quote from en.cppreference, see Danh's answer for the standard), the rule is as follow:
There can be more than one definition in a program, as long as each definition appears in a different translation unit, of each of the following: class type [...], as long as all of the following is true:
each definition consists of the same sequence of tokens (typically, appears in the same header file)
[...]
If all these requirements are satisfied, the program behaves as if there is only one definition in the entire program. Otherwise, the behavior is undefined.
Your two definitions clearly violates the first condition, so the behavior is undefined.

From basic.def.odr, (... is omitted by me):
There can be more than one definition of a class type (Clause [class]), ..... Given such an entity named D defined in more than one translation unit, then:
each definition of D shall consist of the same sequence of tokens; and
...
If D is a template and is defined in more than one translation unit, then the preceding requirements shall apply both to names from the template's enclosing scope used in the template definition ([temp.nondep]), and also to dependent names at the point of instantiation ([temp.dep]). If the definitions of D satisfy all these requirements, then the behavior is as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.
In your program, definition of struct Data in td_collision1.cc and in td_collision2.cc doesn't match with each other, hence, definitions of struct Data do not satisfy those requirements, then the behavior is undefined.

Well, you're linking a C answer, but your question is about C++. Two languages, two standards, two answers.
That said, I believe the C answer should also be that it's disallowed, per the One Definition Rule (which both languages have). Violating that is Undefined Behavior, which includes Segmentation Faults.

Related

Memory Leak caused by Initializer List?

I'm having memory leaks in my code, according to valgrind all of them come from the constructor in my class; here its code:
School::School(unsigned int NumberOfClasses[]) :
first(*new Grade<Student, std::equal_to<Student>>(NumberOfClasses[0])),
second(*new Grade<Student, std::equal_to<Student>>(NumberOfClasses[1])),
third(*new Grade<Student, std::equal_to<Student>>(NumberOfClasses[2])) {
}
Grade is a special array template I created that gets both an element (in this case, a Student) and a compare function for the element (which I also provided); it has both a Constructor and a Destructor that works without memory leaks. Here is the signature of the constructor:
Grade<Element, Compare> :: Grade(unsigned int size);
Since my school is 3 Grades, its destructor is =default;
This is what I get from valgrind:
8 bytes in 1 blocks are indirectly lost in loss record 1 of 6
==21426== at 0x4C2A888: operator new[](unsigned long) (vg_replace_malloc.c:423)
==21426== by 0x4041B8: Grade<BmbSchool::Student, std::equal_to<BmbSchool::Student> >::Grade(unsigned int) (GradeImp.h:9)
==21426== by 0x40298B: BmbSchool::School::Grade(unsigned int*) (School.cpp:27)
==21426== by 0x405B6C: main (BmbSchool.cpp:148)
Another kind of error I get, quite similiar, is:
==21426== 32 (24 direct, 8 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 6
==21426== at 0x4C2A1E3: operator new(unsigned long) (vg_replace_malloc.c:334)
==21426== by 0x402974: BmbSchool::School::Grade(unsigned int*) (School.cpp:28)
==21426== by 0x405B6C: main (BmbSchool.cpp:148)
Any way it makes sense? How can I solve this? I can assume that there won't be any bad_alloc exceptions thrown when defining the arrays.
edit: The definition to school is -
Grade<Student, std::equal_to<Student>> first;
Grade<Student, std::equal_to<Student>> second;
Grade<Student, std::equal_to<Student>> third;
The leak is in your misuse of new. You are dynamically allocating 3 Grade objects, but are then dereferencing the pointers to pass those objects to the copy constructor of your 3 data members. You never delete the objects you new'ed, hence the leaking.
You don't need to use new at all in this situation. Simply pass your input values directly to the same constructor of the data members themselves that you were calling with new:
School::School(unsigned int NumberOfClasses[]) :
first(NumberOfClasses[0]),
second(NumberOfClasses[1]),
third(NumberOfClasses[2])
{
}
If you can use C++11 or later, you can use std::array, so something like
School::School(const std::array<unsigned int, 3>& NumberOfClasses) :
// as Remy Lebeau's answer
I would expect compilers to produce similar if not the same machine code, but you will gain some compile-time checking.

Newbie in vectors in C++

I am trying to understand how vectors work. From what I ve read they are a class that can be used as an array with many helpful functions to handle its elements. So I ve tried creating a vector of a class A which contains a vector of class B.
Here is the code:
#include <iostream>
#include <vector>
using namespace std;
class B
{
public:
B()
{}
void print()
{
cout<<"The mighty ";
}
~B()
{}
};
class A
{
B b;
vector<B> Blist;
public:
A()
{
cout<<"An A!"<<endl;
}
void pushb()
{
Blist.push_back(b);
}
void printb()
{
Blist[7].print();
}
void print()
{
cout<<"Kass Company"<<endl;
}
~A()
{
}
};
int main(void)
{
vector<A> Alist;
A a, b, c;
Alist.push_back(a);
Alist[1].printb();
Alist[1].print();
return 0;
}
Well, my problem is that... it works fine. If vectors work like arrays shouldnt the first object that gets pushbacked get the 0 position of the vector? As a result, shouldnt the program fail to run, since there is no object in the Alist[1] or the Blist[7]?
Thanks in advance!
Well, my problem is that... it works fine
Well, in fact it shouldn't, since you're accessing both Alist and Alist::Blist out of their bounds.
If vectors work like arrays shouldnt the first object that gets pushbacked get the 0 position of the vector?
The std::vector<T>::push_back function appends an element to the end of the vector, so the push-backed element is given the index size() - 1 (after the push, e.g. the old size()).
Check your bounds
When using std::vector, you are responsible for checking the bounds you're trying to access to. You can use std::vector<T>::size() for this check, or the function std::vector<T>::at(size_t) as said by Jarod42.
See the STL documentation for more information : http://www.cplusplus.com/reference/vector/.
Why it seems to work anyway
You're stumbling across undefined behavior but still, it seems to work fine. Why ?
Well, internally the vector holds a pointer to dynamically allocated memory, holding the vector contents. The class encapsulates all the nasty memory management (calling new, delete, resizing the array, etc.).
When you're calling std::vector<T>::operator[](size_t), by doing for example Alist[1], it simply boils down to dereferencing the internal array at the given index (without bound checking).
Using a bad index, you end up reading some memory past the end of the allocated region, that does not contain any meaningful data, and is probably either uninitialized or zero'ed out. In conclusion when you're doing Alist[1], you're getting some garbage memory interpreted as an A instance.
Now why the hell doing Alist[1].print() does not crash ? Because the function A::print() is not using of the class members, and doing a->print() simply does not uses a contents.
You can verify this using this program (please don't actually use this, it is just intended for this demonstration) :
int foo = 0xDEADBEEF;
A& z = static_cast<A&>(*((A*) &foo));
z.print();
This code simply uses the memory occupied by the integer value foo as an A instance (much like you're using uninitialized memory when accessing the vector out of bounds), and calls the A::print() function.
You can try this for yourself, it works as expected ! This is because this member function does not need to use the actual memory content of the instance, and will run no matter z points to garbage or not.
How to debug and check this program
Use valgrind (http://valgrind.org/). Definitely.
Using valgrind's memcheck, you can track down invalid reads and writes (as well as other memory related stuff) :
you$ valgrind --tool=memcheck a.out
==1785== Memcheck, a memory error detector
==1785== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==1785== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==1785== Command: ./a.out
==1785==
An A!
An A!
An A!
==1785== Invalid read of size 8
==1785== at 0x400F14: std::vector<B, std::allocator<B> >::operator[](unsigned long) (stl_vector.h:771)
==1785== by 0x400E02: A::printb() (main.c:34)
==1785== by 0x400C0D: main (main.c:51)
==1785== Address 0x5a12068 is 8 bytes after a block of size 32 alloc'd
==1785== at 0x4C28965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==1785== by 0x4022E5: __gnu_cxx::new_allocator<A>::allocate(unsigned long, void const*) (new_allocator.h:104)
==1785== by 0x401D20: std::_Vector_base<A, std::allocator<A> >::_M_allocate(unsigned long) (in /home/amonti/.local/share/people/temp/a.out)
==1785== by 0x4013F8: std::vector<A, std::allocator<A> >::_M_insert_aux(__gnu_cxx::__normal_iterator<A*, std::vector<A, std::allocator<A> > >, A const&) (vector.tcc:345)
==1785== by 0x401017: std::vector<A, std::allocator<A> >::push_back(A const&) (stl_vector.h:913)
==1785== by 0x400BF4: main (main.c:50)
==1785==
The mighty Kass Company
==1785==
==1785== HEAP SUMMARY:
==1785== in use at exit: 0 bytes in 0 blocks
==1785== total heap usage: 1 allocs, 1 frees, 32 bytes allocated
==1785==
==1785== All heap blocks were freed -- no leaks are possible
==1785==
==1785== For counts of detected and suppressed errors, rerun with: -v
==1785== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 3 from 3)
In this trace valgrind detects an invalid read (of size 8 because you're reading a pointer on a 64-bit platform) at main.c:34 :
Blist[7].print();
So you can verify that you're doing something wrong.
in your case the output maybe a trash result because the logic of the vector data structure is that its a dynamic array that expands it self(by a constant range ) when it reaches the last free space .
for example when first creating a vector it has 10 spaces when it reaches the 10 space it becomes 20 and in this stage the vec[11] has a trash value.
This is exactly why you're supposed to use vector::at() instead of vector::operator[] when you're testing/writing your program for the first time.
You can use macros and preprocessor defines to declare that you're compiling for debug, such as:
#ifdef THISISDEBUG
return myvec.at(5);
#else
return myvec[5];
#endif
Then you tell your makefile to define THISISDEBUG when you're debugging/testing.
The difference between at() and operator[], is that at() throws an exception if you're out of range, while operator[] accesses memory directly.
In C++, you're generally allowed to read any place in memory (at least in Windows and Linux), but you're only allowed to write into places that belong to your program. Your operating system protects you! Imagine you do what you did up there, and you try to modify something that doesn't belong to your proram. Back then in the 80s and 90s, this would've been accepted and would've lead to a blue screen. Now, your operating system raises a SEGFAULT.
On the other hand, the reason why you're seeing a result there, is because deleting an object doesn't necessarily mean resetting values in memory. It just means that your program tells the operating system: "look, I don't need this region of memory anymore". So, your operating system can assign this region to another program. So, if you try to read that region again, it will work, but you'll get garbage! That's exactly what this technically is called. Like when you do:
double x;
std::cout << x << std::endl;
What is the value that will be printed? It's garbage. It's the remnant of some other program that freed that memory.
Basicly vectors are arrays class.
vector <string> arr; // defines that this is array
vector <MyClass *> arrw; // defines that this is array to my created class vector
Vector is useful to use, when you don't know how much array elements you need. For example, read lines from file. To add new element to vector you can use arr.insert(arr.end(), ""); and add.insert(arr.end(), new MyClass); (I like this better then push_back, becouse You can insert in any place of vector.)
You can access you array element by the same way:
arr[2];
Also it's useful to know some tricks like get access to last element; arr[arr.size() - 1] i. (arr.size() will return INT [elements in array]. And -1 will count it for good index. Othewise you will get segmentation error).
P.S. There is no difference between vector Class and array, ecxept this methods, that allow add new elements, when you don't know how big your array will be.

memory leaks and errors in Valgrind

I am a beginner of C++, and still very confused if I correctly freed memories and removed possible dangling pointers. It was one of my school assignments in the past. There were so many students have the same problems, and no one else could help me.
Please identify where I have problems.
==25334== Mismatched free() / delete / delete []
==25334== at 0x4006D21: free (vg_replace_malloc.c:446)
==25334== by 0x80492F2: HashTable::~HashTable() (Hash.c:115)
==25334== by 0x8049145: SymTab::~SymTab() (SymTab.h:9)
==25334== by 0x8048E9D: main (Driver.c:170)
==25334== Address 0x402c0b8 is 0 bytes inside a block of size 12 alloc'd
==25334== at 0x4007862: operator new(unsigned int) (vg_replace_malloc.c:292)
==25334== by 0x8048C73: main (Driver.c:143)
==25334==
==25334==
==25334== HEAP SUMMARY:
==25334== in use at exit: 18 bytes in 4 blocks
==25334== total heap usage: 10 allocs, 6 frees, 106 bytes allocated
==25334==
==25334== 18 bytes in 4 blocks are definitely lost in loss record 1 of 1
==25334== at 0x4007D58: malloc (vg_replace_malloc.c:270)
==25334== by 0x97E96F: strdup (strdup.c:43)
==25334== by 0x8048FDC: UCSDStudent::UCSDStudent(char*, long) (Driver.c:36)
==25334== by 0x8048C92: main (Driver.c:143)
==25334==
==25334== LEAK SUMMARY:
==25334== definitely lost: 18 bytes in 4 blocks
==25334== indirectly lost: 0 bytes in 0 blocks
==25334== possibly lost: 0 bytes in 0 blocks
==25334== still reachable: 0 bytes in 0 blocks
==25334== suppressed: 0 bytes in 0 blocks
==25334==
==25334== For counts of detected and suppressed errors, rerun with: -v
==25334== ERROR SUMMARY: 5 errors from 2 contexts (suppressed: 15 from 8)
Base.h
#ifndef BASE_H
#define BASE_H
#include <iostream>
using namespace std; /* C error */
/* TEMPLATE */
struct Base { /* C++ struct is public class, public methods */
/* PUBLIC SECTION */
/* virtual: candidates for redefinition */
virtual operator char * (void) {
return 0;
}
virtual operator long (void) { // hash function
return 0;
}
virtual long operator == (Base & base) {// isequal function
return *this == base;
}
Base (void) {} // new_element
virtual ~Base (void) {} // delete_element
virtual ostream & Write (ostream & stream) = 0;// write_element
};
#endif
Driver.c
class UCSDStudent : public Base { /* extends Base */
char * name;
long studentnum;
public:
UCSDStudent (char * nm, long sn) :
name (strdup (nm)), studentnum (sn) {} /* Initialization */
~UCSDStudent (void) { /* Destructor */
free (name);
}
Hash.c
/* HashTable constructor */
HashTable :: HashTable (int sz) : size (sz),
table_count(++counter), occupancy (0), table (new Base *[sz]),
probeCount (new int[sz])
HashTable :: ~HashTable (void)
{
/* call function to delete individual elements */
for(int index2 = 0; index2 < size; index2++)
{
if(table[index2] != NULL)
{
free(table[index2]);
table[index2] = NULL;
}
delete table[index2];
}
/*
* delete table itself
* Freed memory
*/
delete[] table;
delete[] probeCount;
/* pointed dangling ptr to NULL */
table = NULL;
probeCount = NULL;
} /* end: ~HashTable */
The two Valgrind errors ("Mismatched free() / delete / delete []" and "18 bytes in 4 blocks are definitely lost") might be related.
In ~HashTable() you call free(table[index2]) which probably means to destroy the UCSDStudent objects (not sure, as you didn't post the whole program, esp. not the code which insert elements into HashTable). I suppose you create UCSDStudent objects with new - and in that case, you also have to use the corresponding destruction method (in this case delete instead of free()). This is the cause for the first Valgrind error.
Furthermore, the free() function will not call the object's destructor, while delete will do that. This would explain why ~UCSDStudent() is not called, causing your program to leak the memory for the student name. So using delete instead of free() in ~HashTable() should solve both errors.
In general, you should try to stay with one way of memory allocation (either malloc()/free() or new/new[]/delete/delete[]). And given that this is a C++ program, new would be the appropriate choice. In the same vein, I'd advise you to remove the strdup() and char* stuff and switch to std::string instead - this would remove another location where you might mix up free() and delete.
You're calling free on memory that appears to have been declared using new, which is the main error coming out of Valgrind there. You also appear to not be following the Rule of Three (although that doesn't appear to be your entire code there).
I would highly recommend you switch to using smart pointers such as std::shared_ptr / std::unique_ptr, and use std::vector / std::array to create containers.
Looks to me like you never call ~UCSDStudent. Unfortunately, it's not possible to tell from the code you have posted, but the destructor itself looks good, so I expect the problem is that the destructor isn't being called.

Possible memory leak using C++ string

Consider the following C++ program:
#include <cstdlib> // for exit(3)
#include <string>
#include <iostream>
using namespace std;
void die()
{
exit(0);
}
int main()
{
string s("Hello, World!");
cout << s << endl;
die();
}
Running this through valgrind shows this (some output trimmed for brevity):
==1643== HEAP SUMMARY:
==1643== in use at exit: 26 bytes in 1 blocks
==1643== total heap usage: 1 allocs, 0 frees, 26 bytes allocated
==1643==
==1643== LEAK SUMMARY:
==1643== definitely lost: 0 bytes in 0 blocks
==1643== indirectly lost: 0 bytes in 0 blocks
==1643== possibly lost: 26 bytes in 1 blocks
==1643== still reachable: 0 bytes in 0 blocks
==1643== suppressed: 0 bytes in 0 blocks
As you can see, there's a possibility that 26 bytes allocated on the heap were lost. I know that the std::string class has a 12-byte struct (at least on my 32-bit x86 arch and GNU compiler 4.2.4), and "Hello, World!" with a null terminator has 14 bytes. If I understand it correctly, the 12-byte structure contains a pointer to the character string, the allocated size, and the reference count (someone correct me if I'm wrong here).
Now my questions: How are C++ strings stored with regard to the stack/heap? Does a stack object exist for a std::string (or other STL containers) when declared?
P.S. I've read somewhere that valgrind may report a false positive of a memory leak in some C++ programs that use STL containers (and "almost-containers" such as std::string). I'm not too worried about this leak, but it does pique my curiosity regarding STL containers and memory management.
Calling exit "terminates the program without leaving the current block and hence without
destroying any objects with automatic storage duration".
In other words, leak or not, you shouldn't really care. When you call exit, you're saying "close this program, I no longer care about anything in it." So stop caring. :)
Obviously it's going to leak resources because you never let the destructor of the string run, absolutely regardless of how it manages those resources.
Others are correct, you are leaking because you are calling exit. To be clear, the leak isn't the string allocated on the stack, it is memory allocated on the heap by the string. For example:
struct Foo { };
int main()
{
Foo f;
die();
}
will not cause valgrind to report a leak.
The leak is probable (instead of definite) because you have an interior pointer to memory allocated on the heap. basic_string is responsible for this. From the header on my machine:
* A string looks like this:
*
* #code
* [_Rep]
* _M_length
* [basic_string<char_type>] _M_capacity
* _M_dataplus _M_refcount
* _M_p ----------------> unnamed array of char_type
* #endcode
*
* Where the _M_p points to the first character in the string, and
* you cast it to a pointer-to-_Rep and subtract 1 to get a
* pointer to the header.
They key is that _M_p doesn't point to the start of the memory allocated on the heap, it points to the first character in the string. Here is a simple example:
struct Foo
{
Foo()
{
// Allocate 4 ints.
m_data = new int[4];
// Move the pointer.
++m_data;
// Null the pointer
//m_data = 0;
}
~Foo()
{
// Put the pointer back, then delete it.
--m_data;
delete [] m_data;
}
int* m_data;
};
int main()
{
Foo f;
die();
}
This will report a probable leak in valgrind. If you comment out the lines where I move m_data valgrind will report 'still reachable'. If you uncomment the line where I set m_data to 0 you'll get a definite leak.
The valgrind documentation has more information on probable leaks and interior pointers.
Of course this "leaks", by exiting before s's stack frame is left you don't give s's destructor a chance to execute.
As for your question wrt std::string storage: Different implementations do different things. Some allocate some 12 bytes on the stack which is used if the string is 12 bytes or shorter. Longer strings go to the heap. Other implementations always go to the heap. Some are reference counted and with copy-on-write semantics, some not. Please turn to Scott Meyers' Effective STL, Item 15.
gcc STL has private memory pool for containers and strings. You can turn this off ; look in valgrind FAQ
http://valgrind.org/docs/manual/faq.html#faq.reports
I would avoid using exit() I see no real reason to use that call. Not sure if it will cause the process to stop instantly without cleaning up the memory first although valgrind does still appear to run.

C++ valgrind possible leaks on STL string

I do not see the reason of the leak below.
#include <iostream>
#include <cstdlib>
int fail(const std::string str)
{
std::cerr<< str << std::endl;
exit(1);
}
const std::string usage()
{
std::string a = "a";
return a;
}
int main()
{
fail(usage());
return 0;
}
Valgrind says:
==7238== 14 bytes in 1 blocks are possibly lost in loss record 1 of 1
==7238== at 0x402377E: operator new(unsigned) (vg_replace_malloc.c:224)
==7238== by 0x40E7C03: std::string::_Rep::_S_create(unsigned, unsigned,
std::allocator<char> const&) (in /usr/lib/libstdc++.so.6.0.10)
==7238== by 0x40E8864: (within /usr/lib/libstdc++.so.6.0.10)
==7238== by 0x40E89D5: std::string::string(char const*, std::allocator<char> const&)
(in /usr/lib/libstdc++.so.6.0.10)
==7238== by 0x80488EC: usage() (main.cpp:12)
==7238== by 0x804897C: main (main.cpp:18)
==7238== LEAK SUMMARY:
==7238== definitely lost: 0 bytes in 0 blocks.
==7238== possibly lost: 14 bytes in 1 blocks.
==7238== still reachable: 0 bytes in 0 blocks.
==7238== suppressed: 0 bytes in 0 blocks.
The problem is in the fail() function. As it exits(), the memory is leaked.
If I comment out exit(1); then there is no possible leak.
Also, if I change the signature from
int fail(const std::string str)
to
int fail(const char* str)
then there is no possible leak as well. I don't like this solution, as I am using fail(string + (LINE)) type of things, but regardless, what is going on here?
I will be happy if someone can explain.
Thanks!
(upps. same question asked before I guess, sorry! Valgrind reports memory leak when assigning a value to a string)
When you call exit(), the destructors of automatic objects (local variables) do not get called.
In your specific example, the std::string destructor is not called, so the memory owned by the std::string is never deallocated.
The reason there is no leak if you have fail() take a const char* is that there is no destructor for const char*; nothing is deallocated when a pointer is destroyed. If the pointer points to dynamically allocated memory, then that memory must be deallocated (by you) before the program exits, otherwise you have a memory leak. If it points to a string literal, then there is no memory leak because string literals have static storage duration (that is, they exist for the entire lifetime of your program).
James McNellis already wrote a correct answer. But I'd like to add some things:
It is always a good thing to write software in a way that it does not have to call exit() - this helps you improve the overall design, specify and understand object lifetimes (except in very special - rather low level - cases..).
As you see here, this is important when using tools like valgrind! A "clean" shutdown procedure makes you feel safe, then everything worked fine, as you expected ;) A clean shutdown procedure in exceptional cases should be a requirement of every software.
You should consider to throw an exception instead of calling some fail() function. When an exception is thrown, the stack will be unwound, so the std::string destructor in your case would be called.