Home

last update: 2024-10-06 at 12:00:11 CEST

Notes C/C++ Development

But I also knew, and forgot, Hoare’s dictum that premature optimization is the root of all evil in programming.

The Errors of TeX
— Donald Knuth

Generic C++

// g++ -o test generic_function.cpp
#include <iostream>
#include <iomanip>
#include <vector>

auto greater = [](int& a, int param){
    return a > param;
};

auto smaller = [](int& a, int param){
    return a < param;
};

auto add = [](double& a, const double b, const double c){
    a = a + b;
    return a > c;
};

template<class Container, typename Lambda, typename... Args>
auto generic(Container& container, const Lambda& lambda, Args ...args)
{
    Container result;
    for(auto& item : container){
        if(lambda(item, std::forward<Args>(args)...) )
            result.push_back(item);
    }
    return result;
}

template<class Container>
static void print(const Container& c){
    for (const auto& i : c)
        std::cout << std::fixed << std::setprecision(2) << i << ' ';
    std::cout << "\n";
}

int main(void){
    std::vector<int> ints = {1, 2, 3, 4, 5, 6, 7};
    print(generic(ints, greater, 3));
    print(generic(ints, smaller, 3));

    std::vector<double> floats = {1.0, 2.0, 3.0, 4.0};
    print(generic(floats, add, 1.5, 3.0));

    return 0;
}

Speed Challenge - Stack vs Heap


class A
{
public:
        A();
        ~A();
        char c[1000000];
};

A::A(){}
A::~A(){}
/*compile: g++ heap_allocate.cpp -o heap-allocate*/

#include <memory>
#include "A.h"

#define LOOPS 100000000

A* get_from_heap()
{
        return new A();
}

void heap_allocate()
{
        for(int i=0; i<LOOPS; i++){
                std::auto_ptr<A> a(get_from_heap());
        }
}

int main()
{
        heap_allocate();
}
Note
you can also use unique_ptr cause auto_ptr is marked as deprecated. then you have to compile with the -std=c++11 flag. But for some reason the execution time of heap-allocate will doubls (0m13.057s)
/*compile: g++ stack_allocate.cpp -o stack-allocate*/

#include "A.h"

#define LOOPS 100000000

A get_from_stack()
{
        return A();
}

void stack_allocate()
{
        for(int i=0; i<LOOPS; i++){
                A a=get_from_stack();
        }
}

int main()
{
        stack_allocate();
}
g++ --version
g++ (Debian 4.7.2-5) 4.7.2

Result

time ./stack-allocate

real    0m0.873s
user    0m0.864s
sys     0m0.004s
time ./heap-allocate

real    0m5.322s
user    0m5.316s
sys     0m0.000s

Why is stack allocation so fast?

  • due to the stacks memory layout memory management requires less book keeping

    • addresses for allocation/freeing arise automatically (First In Last Out)

    • only one pointer (the stack pointer) has to be moved to point to a new address

  • stack allocation is hot, the memory is more likely to be in cache

  • heap allocation may first search for a free and big enough memory hole

    • the kernel has to be asked. It may split/merge/reuse/frees memory

Inheritance

#include <iostream>
using namespace std;

class Z
{
public:
        char x;
        Z(){x='Z'; cout << "Z()" << endl;}
};

class B: public Z
{
public:
        B(){x='B'; cout << "B()" << endl;}
};

class A: public Z
{
public:
        A(){x='A'; cout << "A()" << endl;}
        A(B b){x='A'; cout << "A(b)" << endl;}
};
/*compile: g++ polymorphism.cpp -o polymorphism -Wall*/
#include "classes.h"
using namespace std;

Z getZasA()
{
        return A();
}

Z getZasB()
{
        return B();
}

A getAasB()
{
        return B();
}

int main()
{
        cout << "a.x = " << A().x << endl;
        cout << "b.x = " << B().x << endl;
        cout << "getZasA().x = " << getZasA().x << endl;
        cout << "getZasB().x = " << getZasB().x << endl;
        cout << "getAasB().x = " << getAasB().x << endl;
}
./polymorphism
Z()
A()
a.x = A
Z()
B()
b.x = B
Z()
A()
getZasA().x = A
Z()
B()
getZasB().x = B
Z()
B()
Z()
A(b)
getAasB().x = A

Conversion

Convert String to Double using Boost

double val;
std::str = "3.1416";
try{
    val = boost::lexical_cast<double>(str);
}
catch (boost::bad_lexical_cast const&){
    val = 0;
}

Wrong Integer Comparison

This small programm shows the problem of comparing a signed integer against an unsigned one. A good compiler like g++ fortunately warns about this if using the switch for example the compiler switch -Wall. These Warnings should be taken serious. Here is why:

warning: comparison between signed and unsigned integer expressions
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <iostream>

using namespace std;
int main(void)
{
    uint64_t u = 5;
    int64_t s = -1;
    if(s < u){
        cout << "s:"<<s<<" is smaller than u:"<<u<<endl;
        return 0;
    }
    cout << "s:"<<s<<" is greater than u:"<<u<<endl;
    cout << "FOOOOOP!"<<endl;
    return 1;
}

The output of the programm is:

s:-1 is greater than u:5
FOOOOOP!

The reason why this happens is that the compiler does convert the singed value s to an unsigned value. Therefore s=18446744073709551615. In such a simple program this might look obvios but in a more complex scenario sometimes the compiler gives important hints. Another example:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <iostream>

using namespace std;
int main(void)
{
    uint64_t u = 5;
    int64_t s = -1;
    if(s-u > 0){
        cout << s-u <<" YEEEE!"<<endl;
        return 0;
    }
    cout << s-u <<endl;
}

The output of the programm is:

18446744073709551610 YEEEE!

Namespaces

Use a Friend Class from a Different Namespace

Suppose we have class A in namespace foo. If we want class B (which is in the global namespace ::) to access private members of A we have to make class B a friend of A somewhere in class A we must define:

friend class B;

But the problem is that both classes reside in different namespaces. The compiler will complain with the very helpful message (g++)

The standats says:

Standard 7.3.1.2 / 3 :

Every name first declared in a namespace is a member of that namespace. If a friend declaration in a nonlocal class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship).

Here is an example of how to access the private variable x inside the class A from function f() which is in class B. The correct way to declare the friendship is friend class ::B; Class B must be accessed via the :: operator to access the global namespace.

File main.cpp
#include <iostream>
#include "B.h"

int main() {
        B b;
        std::cout << b.f() << std::endl;
        return 0;
}
File A.h
class B;

namespace foo{
        class A{
                friend class ::B;
                private:
                int x;
        };
}
File B.h
#include "A.h"

class B {
        public:
        foo::A a;
        int f()
        {
                return a.x;
        }
};

Compile this with the command e.g.

g++ -Wall -pedantic main.cpp -o friends

string Manipulation

The c++ programming language often offers multiple ways for the same task.

How to Declare a Static Const String as Class Member

In Java we can easily write:

public class A
{
        static final String woo = "This is why";
}

in c++ we can only initialize static const member variables like int i=10; within our class (integral types). Otherwise we will get a compiler error like: invalid in-class initialization of static data member of non-integral type 'std::string'. → The correct way is to declare the member variable inside the class, but initialize it outside of the class. For example:

Header file A.h

class A
{
private:
        static const char woo[];
}

Source file A.cpp

const char A::woo[] = "This is why";
Note
I would suggest to always prefer a const char* over a const std::string for string constants unless there are good reasons against it. Because if you write const std::string boo = "Hi!" the constructor of boo will be called just before the execution of main() (a std::string requires dynamic initialization) and additionally the constructor will create a copy of boo on the heap. All this is avoided if using a const char*.

Get String Lenght equivalent for a Char Array

If we declare std::string A we can use the A.lenght() mehtod to get the number of characters of the string. If we declare char B[10] we can use the mehtod int strlen(char *) to get the lenght.

std::string A = "test"
char B[] = "test"

A.lenght()
strlen(B)

in both cases the length is 4

Search for Memory Leaks

Valgrind is a good tool for identifying memory leaks

Valgrind

valgrind --leak-check=full --show-reachable=yes -v

Pmap

Constantly print an overview of allocated pages by a pid or a group of them. The tool pmap reveals the memory allocated by malloc or mmap (anon region)

while true; do for pid in $(pidof luxconsole); do echo $pid; pmap $pid | grep
anon ;done;sleep 1;done

Enable Core Dumps

Set the core file size to unlimited. Note: ulimit -a shows the current user limits.

ulimit -S -c unlimited > /dev/null 2>1

Debugging

gdb - The GNU Debugger

How to print a STL vector:

print *(vector._M_impl._M_start)@vector.size()

This only print N elements of the vector:

print *(vector._M_impl._M_start)@N

Print a backtrace of all running threads:

threads apply all backtrace
Note
this is the same but shorter: thr a a bt
How to track down a double free():

set the MALLOC_CHECK_ environment variable to 2, this will cause glibc to use an error tolerant version of malloc, which will cause your program to abort at the point where the double free is done.

You can set this from gdb by using the set environment MALLOC_CHECK_ 2 command before running your program; the program should abort, with the free() call visible in the backtrace.

GCC Compiler Errors

A collection of compiler errors and how to fix them

Problem
error: ISO C++ forbids declaration of 'int64_t' with no type
Solution
#include <stdint>
Problem
error: 'cout' was not declared in this scope
Solution
#include <iostream>
using namespace std;
Problem accessing private member
In file included from B.h:1:0,
                 from main.cpp:2:
A.h: In member function ‘int B::f()’:
A.h:7:7: error: ‘int foo::A::x’ is private
In file included from main.cpp:2:0:
B.h:8:12: error: within this context
Solution

see here