Memory Leak caused by Initializer List? - c++

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.

Related

free std::string member of a struct allocated using malloc

I am writing a c++ code. As a part of it, I use a C library quickjs.
This library allows creating dynamic memory using its custom js_mallocz call (which internally uses malloc), and freeing it later with js_free call.
I have a struct like this :
struct Person{
std::string id;
unsigned short age;
};
Which I have created using js_mallocz call, which is freed using the proper call.
//while assigning
auto person = (Person*) js_mallocz(ctx,sizeof(Person));
sole::uuid u4 =sole::uuid4();
std::string u = u4.base62();
person->id=u;
person->age=40;
//while freeing
js_free(ctx,person);
A code like this would give an error like :
24 bytes in 1 blocks are definitely lost in loss record 1 of 2
==30236== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==30236== by 0x49D93FE: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.29)
==30236== by 0x11F93B: assign (basic_string.h:1370)
==30236== by 0x11F93B: operator= (basic_string.h:700)
I can't use new operator as I am required to use the memory allocation done by the third party lib quickjs. How do one free std::string in such struct created using malloc ?
Placement new is the way to solve this issue. (Concluded it based on from comments from #drescherjm)
So the code should be :
//while assigning
auto person = (Person*) js_mallocz(ctx,sizeof(Person));
person = new(person) Person(); //Placement new
sole::uuid u4 =sole::uuid4();
std::string u = u4.base62();
person->id=u;
person->age=40;
//while freeing
person->~Person(); //Manually call destructor
js_free(ctx,person);
Redefine your global operator new (all relevant varieties) in terms of js_mallocz and corresponding operator delete in terms of js_free.
Placement new is not a solution, because the C++ standard library and any third-party C++ library you happen to use will happily keep allocating memory for their internal needs with operator new. Not even speaking about needing to rewrite all of your code in this horrible style.

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.

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

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.

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.