# 582484 Algorithm Libraries

## Exercise 5 solutions

1. Checksum using exclusive-or:

```#include <numeric>
#include <vector>
#include <iostream>
#include <iterator>
#include <boost/lambda/lambda.hpp>

struct xor_functor : public std::binary_function<int,int,int>
{
int
operator()(int a, int b) const { return a^b; }
};

int main()
{
int sum;
int temp[] = {12, 43, 23, 1, 102, 20};
int n = sizeof(temp)/sizeof(temp);
std::vector<int> v(temp, temp+n);
std::copy(v.begin(), v.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;

// using our own functor
sum = std::accumulate(v.begin(), v.end(), 0, xor_functor());
std::cout << "Checksum is " << sum << std::endl;

// using boost lambda library
using boost::lambda::_1;
using boost::lambda::_2;
sum = std::accumulate(v.begin(), v.end(), 0, _1 ^ _2);
std::cout << "Checksum is " << sum << std::endl;

return 0;
}

```
2. You can use valgrind to test whether your program leaks memory or not. The program is installed on department's linux machines. Typical usage looks like:

valgrind --tool=memcheck --leak-check=yes a.out

Try it before and after changing the list example.

1. Releasing allocated memory after nodes are no longer used, can be done, for instance, using a recursive destructor. When the head of the list is deleted, the node pointed to by the next pointer will be deleted recursively. This process stops when the end of the list is reached (next == 0).

```~node() {
std::cout << "-------- deleting " << val << std::endl;
delete next;
}
```

When deleting single elements using erase_after, we have to be careful not to delete the whole end part of the list. Therefore, the next field of the node to be deleted is first set to zero:

```void erase_after (iterator iter) {
node* p = iter.ptr;
if (p==0) { p = &head; }
if (p->next != 0) {
node* tmp = p->next;
p->next = p->next->next;
tmp->next = 0;
delete tmp;
}
}
```
2. When using the boost smart pointers, we don't explictly need to delete the nodes. We just have to use smart pointers instead of raw pointers. But note that in iterator, we still use raw pointers. This is because we don't want iterators to own the elements they point to. If we have an iterator pointing to an element, and when we delete the element, the iterator gets invalidated and should not be used.

boost::shared_ptr is very strict about making implicit conversions between raw and smart pointers. That's why we need to add a few explicit calls to the constructor and the get() member function, which returns the raw pointer.

```
#include <algorithm>
#include <iterator>
#include <iostream>
#include <boost/shared_ptr.hpp>

struct slist {

struct node;
typedef boost::shared_ptr<node> node_ptr;

// implicit destructor

private:
slist (const slist&);            // no copy constructor
slist& operator= (const slist&); // no copy assignment

public:

struct node {
int val;
node_ptr next;

node (int i, node_ptr n) : val(i), next(n) {}
~node() { std::cout << "-------- deleting " << val << std::endl; }
// implicit copy constructor, copy assignment
// no default constructor
};

struct iterator
: std::iterator<std::forward_iterator_tag, int>
{
node* ptr;

iterator (node* p = 0) : ptr(p) {}
// implicit copy constructor, copy assignment and destructor

reference operator* () { return ptr->val; }

iterator& operator++ () { ptr = ptr->next.get(); return *this; }
iterator operator++ (int) {
iterator tmp = *this; ++*this; return tmp; }

bool operator== (const iterator& other) const {
return ptr == other.ptr;
}
bool operator!= (const iterator& other) const {
return ptr != other.ptr;
}
};

iterator begin() { return iterator(head.next.get()); }
iterator end()   { return iterator(); }

// insert a node after iter, or to the beginning if iter==NULL
void insert_after (iterator iter, int val) {
node* p = iter.ptr;
if (p==0) { p = &head; }
p->next.reset(new node(val, p->next));
}

// erase iter+1 or the first node if iter==NULL
// if iter points to last node or list is empty, nothing is erased
void erase_after (iterator iter) {
node* p = iter.ptr;
if (p==0) { p = &head; }
if (p->next.get() != 0) p->next = p->next->next;
}

};

int main() {

slist c;
c.insert_after(0, 2);          // [ 2 ]
c.insert_after(c.begin(), 3);  // [ 2 3 ]
c.insert_after(0, 1);          // [ 1 2 3 ]

std::copy (c.begin(), c.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;

c.erase_after(c.begin());      // [ 1 3 ]
c.erase_after(c.begin());      // [ 1 ]

std::copy (c.begin(), c.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;

}

```