Newbie question. I am trying to program a binary search tree, but even
a simple insert has a memory leak.
File Node.h
template<typename X> struct Node {
X value;
Node* left;
Node* right;
Node(X x) {
this->value = x;
this->left = nullptr;
this->right = nullptr;
}
};
File BST.h
template <typename X> class BST {
public:
BST() { root = nullptr; }
bool Insert(const X& x) { return InsertAt(root, x); }
private:
bool InsertAt(Node<X>*& node, const X& x)
{
if (node == nullptr) {
node = new Node<X>(x);
return true;
}
if (node->value == x)
return false;
if (*(node->value) > *x)
return InsertAt(node->left, x);
return InsertAt(node->right, x);
}
//----
Node<X>* root;
};
The main program
#include "Node.h"
#include "BST.h"
int main(int argc, char **argv)
{
BST<int*> bst;
bst.Insert(new int(8));
}
The output of g++ -g -fsanitize=address -fno-omit-frame-pointer -std=c++11 B.cpp
==10646==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 24 byte(s) in 1 object(s) allocated from:
#0 0x7fb5e7f45532 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x99532)
#1 0x400eb7 in BST<int*>::InsertAt(Node<int*>*&, int* const&) /home/gc/BST.h:12
#2 0x400e68 in BST<int*>::Insert(int* const&) /home/gc/BST.h:5
#3 0x400d09 in main /home/gc/B.cpp:22
#4 0x7fb5e778082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
Indirect leak of 4 byte(s) in 1 object(s) allocated from:
#0 0x7fb5e7f45532 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x99532)
#1 0x400caf in main /home/gc/B.cpp:22
#2 0x7fb5e778082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
SUMMARY: AddressSanitizer: 28 byte(s) leaked in 2 allocation(s).
First, why am I getting a memory leak? Second, why am I getting a message
about new(unsigned long) when there is nothing unsigned long about my program?
Thanks.
You may tell me to use smart pointers, but for right now I'm just trying to
educate myself about pointers and trying to figure out why this doesn't work.
If you're not going to use smart pointers, then you have to pair every new with a delete. Since your calls to new happen in each class's constructor, you can delete in the destructor.
Anyways, in BST the destructor should be
~BST() { delete root; }
And in Node, it's
~Node() { delete left; delete right; }
This will recursively work it's way down the tree. Your recursive case is when a pointer to a node is not null. Unlike with free which crashes on a null, delete simply does nothing, making nullptr your base case.
Check out http://en.cppreference.com/w/cpp/language/destructor
Related
I created a class "config" that contains 12 bool values, organized in a std::array. The class has an "icing" function that returns a double value.
Trying to order a vector of 2^12 (4096) configs through a std:: sort (contained in #include ) using a predicate i have written, i get a segmentation fault error.
Shrinking the vector to 205 (not 1 more) eliminates the error, but I don't know why.
If i make the vector 4096 long, and try to sort only a little part, it works until the part is long 175+.
Shrinking the vector to for example around 1000, limits the partial sorting to around 20, before it gives the segmentation error.
#include <array>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
class config {
public:
config (){ //constructor, default
array<bool,12> t;
for (bool& b: t){
b=false;
}
val=t;
g=1;
}
config (const config& fro): val(fro.val){}; //copy constructor
array<bool,12> get_val(){ return val; } //returns the array
void set_tf(int n, bool tf){ val[n]=tf; } //sets a certain boolean in the array to false/true
void set_g(double d){ g=d; } //this sets the constant for calculation to a number
void print(){
cout<<"values: ";
for (auto b: val){ cout<<b<<" "; }
cout<<endl;
}
config & incr(int n=1){ //this increases the vector by 1 following the rules for binary numbers, but has the digits reversed
for(int j=0; j<n; j++){
int i=0;
bool out=false;
while(val[i]==true){
val[i]=false;
i++;
}
val[i]=true;
}
return *this;
}
double energy(){
int ct=0;
int cf=0;
for(auto b:val){ if(b==true){ ct++; } else { cf++; } }
return (abs(ct-cf));
}
double icing(){ //here is the "value" for ordering purposes
int n=0;
for(int i=0; i<11; i++){
if(val[i]!=val[i+1]){ n++; }
}
double temp=-g*n+this->energy();
return temp;
}
private:
array<bool,12> val;
double g;
};
bool pred (config c1, config c2){ return c1.icing()>c2.icing(); } //this sets the ordering predicate
template <typename T> //this orders the vector
void csort (vector <T>& in){
sort(in.begin(), in.end(), pred);
}
int main(){
vector<config> v;
for (int i=0; i<4096; i++){ //cicle that creates a vector of successive binaries
for(auto& c:v){
c.incr();
}
config t;
v.push_back(t);
}
sort(v.begin(), v.begin()+174, pred); //this gives seg.fault when 175+
csort(v); //this gives segmentation fault when the vec is 206 long or longer
}
I expected the code to order the vector, but it goes into segmentation fault.
Your program has undefined behaviour in sort function because your predicate takes config by value, so copies are made and in this place copy constructor is called which copies only array val, but not g.
bool pred (config c1, config c2){ return c1.icing()>c2.icing(); }
// takes by value, copy ctor is called
config (const config& fro): val(fro.val){}; // only val is copied, g HAS GARBAGE VALUE
// icing in pred uses g !! - stric weak ordering is violated because g has GARBAGE VALUE
Fix 1:
pass config by const config&:
bool pred (const config& c1, const config& c2){ return c1.icing()>c2.icing(); }
or fix 2:
g is initialized in copy constructor:
config (const config& fro): val(fro.val), g(fro.g){};
I'm wondering if it's possible to hint to gcc that a pointer points to an aligned boundary. if I have a function:
void foo ( void * pBuf ) {
uint64_t *pAligned = pBuf;
pAligned = ((pBuf + 7) & ~0x7);
var = *pAligned; // I want this to be aligned 64 bit access
}
And I know that pBuf is 64 bit aligned, is there any way to tell gcc that pAligned points to a 64 bit boundary? If I do:
uint64_t *pAligned __attribute__((aligned(16)));
I believe that means that the address of the pointer is 64 bit aligned, but it doesn't tell the compiler that the what it points to is aligned, and therefore the compiler would likely tell it to do an unaligned fetch here. This could slow things down if I'm looping through a large array.
There are several ways to inform GCC about alignment.
Firstly you can attach align attribute to pointee, rather than pointer:
int foo() {
int __attribute__((aligned(16))) *p;
return (unsigned long long)p & 3;
}
Or you can use (relatively new) builtin:
int bar(int *p) {
int *pa = __builtin_assume_aligned(p, 16);
return (unsigned long long)pa & 3;
}
Both variants optimize to return 0 due to alignment.
Unfortunately the following does not seem to work:
typedef int __attribute__((aligned(16))) *aligned_ptr;
int baz(aligned_ptr p) {
return (unsigned long long)p & 3;
}
and this one does not either
typedef int aligned_int __attribute__((aligned (16)));
int braz(aligned_int *p) {
return (unsigned long long)p & 3;
}
even though docs suggest the opposite.
If I pass a container by constant reference, is there a point in declaring a constant reference in a range-for loop, or will the elements in the loop automatically inherent that property?
i.e.
int foo(std::vector<int> const& vec) {
for (int const& el : vec)
// do something...
}
is the above equivalent to:
int foo(std::vector<int> const& vec) {
for (int el : vec)
// do something...
}
For a trivial scalar like an int, a const reference is just overhead - behind the scenes references are implemented with pointers, so a reference is really just a compiler-managed pointer and accessing it requires a dereference.
#include <vector>
extern void f1(int);
extern void f2(int const&);
int foo1(std::vector<int> const& v) {
for (int const& val: v) {
f1(val);
f2(val);
}
}
int foo2(std::vector<int> const& v) {
for (int val: v) {
f1(val);
f2(val);
}
}
Assembly output
foo2 produces this:
movl (%rbx), %edi ; val = *it
addq $4, %rbx ; ++it
movl %edi, 12(%rsp) ; save val on stack
call f1(int)
leaq 12(%rsp), %rdi ; load address of saved val
call f2(int const&)
Note the leaq for calling f2. We took a simple copy of the current vector value into edi, but then we also had to push it onto the stack so we could get an address to comply with the reference requirement for f2.
However in a different example, the compiler is perfectly capable of figuring out that a reference wasn't needed and just doing the right thing:
#include <vector>
#include <atomic>
int total;
int foo1(std::vector<int> const& v) {
for (int const& val: v) {
total += val;
}
}
int foo2(std::vector<int> const& v) {
for (int val: v) {
total += val;
}
}
both functions produce the same code, the compiler eliminated the reference.
Below is the program which converts a sorted Array to BST. I am able to compile and execute the program using an online C compiler. When I tried the compile on my local system, it is throwing a segmentation fault.
SortedArraytoBST.c
#include <stdio.h>
#include <stdlib.h>
// Structure of the node
struct TNode
{
int data;
struct TNode* left;
struct TNode* right;
};
struct TNode* newNode(int data);
// Function that converts array to BST
struct TNode* SortedArrayToBST(int arr[], int start, int end)
{
if(start > end)
{
return NULL;
}
if(start == end)
{
struct TNode* newnode2 = newNode(arr[start]);
return newnode2;
}
int mid = (start+end)/2;
struct TNode* newnode = newNode(arr[mid]);
newnode->left = SortedArrayToBST(arr, start, mid-1);
newnode->right = SortedArrayToBST(arr, mid+1, end);
return newnode;
}
//NewNode Creation
struct TNode* newNode(int data)
{
struct TNode* node = (struct TNode*)malloc(sizeof(struct TNode*));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
// Print the tree in preorder
void preorder(struct TNode* node)
{
if( node == NULL) return;
printf("%d\n", node->data);
preorder(node->left);
preorder(node->right);
}
// Array to BST
int main()
{
int arr[]={1,2,3};
int size = sizeof(arr)/sizeof(arr[0]);
struct TNode* root = SortedArrayToBST(arr, 0, size-1);
preorder(root);
return 0;
}
Command used to compile the program
$ gcc -o SortedArraytoBST SortedArraytoBST.c
$ gcc --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.2.0
Thread model: posix
$
Output of the program on my local Mac
2
-398445936
Segmentation fault: 11
Output of the program on http://code.geeksforgeeks.org/
2
1
3
Line 36, you have a wrong allocation causing a heap-buffer-overflow.
You should write:
struct TNode* node = (struct TNode*)malloc(sizeof(struct TNode));
instead of:
struct TNode* node = (struct TNode*)malloc(sizeof(struct TNode*));
HOW TO DEBUG IT
If you get gcc 4.8 or above, you can run address sanitizer:
gcc -fsanitize=address -fno-omit-frame-pointer -g myprogram.c -o myprogram
What I got:
=================================================================
==22711==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000eff8 at pc 0x000000400bbb bp 0x7ffea7e3c630 sp 0x7ffea7e3c628
WRITE of size 8 at 0x60200000eff8 thread T0
#0 0x400bba in newNode /home/jyvet/TMP/myprogram.c:38
#1 0x400aac in SortedArrayToBST /home/jyvet/TMP/myprogram.c:27
#2 0x400d75 in main /home/jyvet/TMP/myprogram.c:57
#3 0x7f68db2c7b44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b44)
#4 0x4008e8 (/home/jyvet/TMP/myprogram+0x4008e8)
0x60200000eff8 is located 0 bytes to the right of 8-byte region [0x60200000eff0,0x60200000eff8)
allocated by thread T0 here:
#0 0x7f68db6e337a in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x9437a)
#1 0x400b59 in newNode /home/jyvet/TMP/myprogram.c:36
#2 0x400aac in SortedArrayToBST /home/jyvet/TMP/myprogram.c:27
#3 0x400d75 in main /home/jyvet/TMP/myprogram.c:57
#4 0x7f68db2c7b44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b44)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/jyvet/TMP/myprogram.c:38 newNode
I'm using gcc 5.1.0 (c++14) and I was trying with constexpr. Is very annoying to verify if the constexpr I've implemented are evaluated at compile time. I couldn't find any flag for get a warning about that situation.
Here is an example:
example.cpp -----------------------------------------
#include <stdlib.h>
const char pruVar[] = "12345678901234567";
[[gnu::noinline]] constexpr unsigned int myStrlen(const char* cstr)
{
unsigned int i=0;
for(;cstr[i]!=0;++i);
return i;
}
struct CEXAMPLE
{
unsigned int size;
constexpr CEXAMPLE(const char* s): size(myStrlen(s))
{
}
};
int main(void)
{
CEXAMPLE c(pruVar);
unsigned int size = myStrlen(pruVar);
void* a = malloc(c.size + size);
if (a != nullptr)
return 0;
else
return 1;
}
In the example CEXAMPLE::CEXAMPLE is evaluated at compile time including the call to myStrlen in it, but the call to myStrlen in main is being evaluated at runtime. The only way I have to know this is looking at the assembler.This website is very useful too: http://gcc.godbolt.org/
If you know how to make the compiler warn about this or something similar I'll appreciate it
myStrlen(pruVar) can be evaluated at compile time; the compiler is just choosing not to in this instance.
If you want to force the compiler to evaluate it at compile time or error if this is not possible, assign the result to a constexpr variable:
constexpr unsigned int size = myStrlen(pruVar);
^^^^^^^^^
You could also use an enum, or a std::integral_constant:
enum : unsigned int { size = myStrlen(pruVar) };
std::integral_constant<unsigned int, myStrlen(pruVar)> size;
Based on the fact that template arguments must be evaluated at compiletime a helper template can be used.
namespace helper {
template<class T, T v> constexpr T enforce_compiletime() {
constexpr T cv = v;
return cv;
}
}
#define compiletime(arg) ::helper::enforce_compiletime<decltype(arg), (arg)>()
This allows compile time enforcement without an additional constexpr variable, which is handy in order to calculate value lookup tables.
constexpr uint32_t bla(uint8_t blub) {
switch (blub) {
case 5:
return 22;
default:
return 23;
}
}
struct SomeStruct {
uint32_t a;
uint32_t b;
};
SomeStruct aStruct = {compiletime(bla(5)), compiletime(bla(6))};