Why does this list implementation take more space than stl list?

shayst

I'm using IAR as compiler for embedded project. I'm trying to introduce some templates for basic types like list, but each STL list object created increases code size by about 200 bytes relatively to our current C style implementation. I tried to implement a small portion of the STL list myself hoping to get a smaller code footprint, but ended up being more heavy than the full STL list. Am I doing something horribly wrong in my usage of templates?

Thanks

P.S. Please note that the code is untested so it may contain dragons.

#ifndef __LINK_LIST_HPP__
#define __LINK_LIST_HPP__

#include <stdint.h>
#include <stdlib.h>

template <typename T> class list
{
private:
    struct LinkListElement
    {
        T payload;
        LinkListElement* next;
        LinkListElement* prev;
    };
public:

    class iterator
    {
        // Need access to LinkListElement struct
        friend class list;
    public:
        iterator() : m_cur_item(NULL){}

        iterator(LinkListElement* elem) : m_cur_item(elem){}

        iterator(const iterator& other) : m_cur_item(other.m_cur_item){}

        ~iterator(){}

        iterator& operator=(const iterator& other)
        {
            m_cur_item = other.m_cur_item;
            return *this;
        }

        bool operator==(const iterator& other) const
        {
            // Compare by position, ignoring the payload contents when comparing iterators.
            return  (m_cur_item->next == other.m_cur_item->next) &&
                    (m_cur_item->prev == other.m_cur_item->prev);
        }

        bool operator!=(const iterator& other) const
        {
            return !(*this == other);
        }

        // Prefix increment operator.
        iterator& operator++()
        {
            increment();
            return *this;
        }

        // Postfix increment operator.
        iterator operator++(int)
        {
            iterator copy(*this);
            increment();
            return copy;
        }

        // Prefix decrement operator.
        iterator& operator--()
        {
            decrement();
            return *this;
        }

        // Postfix decrement operator.
        iterator operator--(int)
        {
            iterator copy(*this);
            decrement();
            return copy;
        }

        T& operator*()
        {
            // Just so we won't crash, but behavior is undefined.
            if (m_cur_item == NULL)
            {
                return dummy;
            }

            return m_cur_item->payload;
        }

        T* operator->()
        {
            if (m_cur_item == NULL)
            {
                return NULL;
            }

            return &(m_cur_item->payload);
        }

    private:

        void increment()
        {
            if (m_cur_item == NULL || m_cur_item->next == NULL)
            {
                return;
            }

            m_cur_item = m_cur_item->next;
        }

        void decrement()
        {
            if (m_cur_item == NULL || m_cur_item->prev == NULL)
            {
                return;
            }

            m_cur_item = m_cur_item->prev;
        }

        LinkListElement* m_cur_item;
        static T dummy;

    };

    // Need access to internal LinkListElement pointer
    friend class iterator;

    list()
    {
        // Add sentinel to mark end of list.
        m_tail = new LinkListElement;
        m_tail->next = m_tail;
        m_tail->prev = m_tail;
        m_head = m_tail;
    }

    ~list()
    {
        // Clear entire list except for sentinel
        clear();

        // Destroy sentinel
        delete m_tail;
        m_head = NULL;
        m_tail = NULL;
    }

    T& back()
    {
        // empty list with only sentinel. Result of back() is undefined
        if (empty())
        {
            // TODO: Show some debug error
        }

        return m_tail->prev->payload;
    }

    T& front()
    {
        if (empty())
        {
            // TODO: Show some debug error
        }

        // m_head is always defined even if list is empty
        return m_head->payload;
    }

    size_t size()
    {
        return m_count;
    }

    bool empty()
    {
        // head == tail means the list is empty
        return m_head == m_tail;
    }

    iterator begin()
    {
        return iterator(m_head);
    }

    iterator end()
    {
        return iterator(m_tail);
    }

    iterator insert(iterator position, const T& payload)
    {
        // Validate position by finding it in our list
        iterator find = begin();
        while (find != end() && find != position)
        {
            ++find;
        }

        if (find == end())
        {
            // TODO: Show some debug error
            return position;
        }

        return insert_before(find.m_cur_item, payload);
    }

    void push_back(const T& payload)
    {
        insert_before(m_tail, payload);
    }

    void push_front(const T& payload)
    {
        insert_before(m_head, payload);
    }

    iterator erase(iterator position)
    {
        // Validate position by finding it in our list
        iterator find = begin();
        while (find != end() && find != position)
        {
            ++find;
        }

        if (find == end())
        {
            // TODO: Show some debug error
            return position;
        }

        return remove_at(find.m_cur_item);

    }

    //iterator erase(iterator first, iterator last);    // Implement only if needed
    void pop_back()
    {
        if (!empty())
        {
            // Don't remove the sentinel
            remove_at(m_tail->prev);
        }
    }

    void pop_front()
    {
        if (!empty())
        {
            remove_at(m_head);
        }
    }

    void remove(const T& value)
    {
        iterator iter = begin();

        while (iter != end())
        {
            iterator remove = iter++;
            if (*remove == value)
            {
                remove_at(remove.m_cur_item);
            }
        }
    }

    void clear()
    {
        while (!empty())
        {
            pop_back();
        }
    }

private:

    iterator insert_before(LinkListElement* existing, const T& payload)
    {
        // Allocate memory and save the element
        LinkListElement* new_elem = new LinkListElement;

        // For classes types (not pointer to object) this should invoke copy constructor
        new_elem->payload = payload;
        new_elem->prev = existing->prev;
        new_elem->next = existing;
        existing->prev = new_elem;
        ++m_count;

        if (existing == m_head)
        {
            m_head = new_elem;
        }

        return iterator(new_elem);
    }

    iterator remove_at(LinkListElement* to_remove)
    {
        // Allocate memory and save the element
        LinkListElement* prev = to_remove->prev;
        LinkListElement* next = to_remove->next;
        prev->next = next;
        next->prev = prev;
        --m_count;

        if (to_remove == m_head)
        {
            m_head = next;
        }

        delete to_remove;

        return iterator(prev);
    }

    LinkListElement* m_head;
    LinkListElement* m_tail;
    uint32_t         m_count;
};

template <typename T> T list<T>::iterator::dummy;

#endif
David Schwartz

You code has all kinds of features and checks that the STL doesn't have. So it makes sense that you would wind up with more code.

Yes, the STL has lots of features your code doesn't have. But you aren't using any of them, so they don't show up in your code footprint. The STL is designed using templates so that you don't pay for what you don't use.

It's unlikely you can improve on the STL. If you need to add features, add them. You don't need to reinvent the wheel.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Why does a char seem to take more space in an array than by itself

From Java

Why does one long string take MORE space than lots of small strings?

From Dev

Why does a disk clone using dd take up more space on the target than the source image?

From Dev

Why does the disk I cloned with Clonezilla take up more space than the source?

From Dev

Why do macros take more space than an equivalently defined function?

From Dev

Why does memoizaion take more time than tabulation?

From Dev

Why does it take more time for a login to fail than to succeed?

From Dev

Why does a String[] takes a lot more space than a char[]?

From Dev

Why does using NEWID() use more space than NEWSEQUENTIALID()?

From Dev

Why does using NEWID() use more space than NEWSEQUENTIALID()?

From Dev

Why does fstrim trim more space than df reports as available

From Dev

Python - Delete items in list with more than one space

From Dev

Why does my linked list only contain one node even though I added more than one?

From Dev

Why does "apt list --all-versions" show more packages than "dpkg -l"?

From Dev

mySQL - Does Int(9.455.487) take more space than string(John) in mySQL?

From Dev

mySQL - Does Int(9.455.487) take more space than string(John) in mySQL?

From Dev

Graphs, vertices, STL lists: Why does list come out empty?

From Dev

Why does this code hang during an insert of stl list

From Dev

Graphs, vertices, STL lists: Why does list come out empty?

From Dev

Python - why is regular expression much more efficient than search in list?

From Dev

List View Does not show more than 10 Item

From Dev

Does '*(&x)' take more work than 'x'

From Dev

Does a subclass take more memory than a superclass

From Dev

Does a subclass take more memory than a superclass

From Dev

Why does a virtual box VM take up more space after I import it?

From Dev

Why does .NET List Sort() not take an explicitly declared delegate object?

From Dev

Why does the delegate take a parameter when no parameter list is specified?

From Dev

Why does .NET List Sort() not take an explicitly declared delegate object?

From Dev

Implementation of non increasing list with STL C++

Related Related

  1. 1

    Why does a char seem to take more space in an array than by itself

  2. 2

    Why does one long string take MORE space than lots of small strings?

  3. 3

    Why does a disk clone using dd take up more space on the target than the source image?

  4. 4

    Why does the disk I cloned with Clonezilla take up more space than the source?

  5. 5

    Why do macros take more space than an equivalently defined function?

  6. 6

    Why does memoizaion take more time than tabulation?

  7. 7

    Why does it take more time for a login to fail than to succeed?

  8. 8

    Why does a String[] takes a lot more space than a char[]?

  9. 9

    Why does using NEWID() use more space than NEWSEQUENTIALID()?

  10. 10

    Why does using NEWID() use more space than NEWSEQUENTIALID()?

  11. 11

    Why does fstrim trim more space than df reports as available

  12. 12

    Python - Delete items in list with more than one space

  13. 13

    Why does my linked list only contain one node even though I added more than one?

  14. 14

    Why does "apt list --all-versions" show more packages than "dpkg -l"?

  15. 15

    mySQL - Does Int(9.455.487) take more space than string(John) in mySQL?

  16. 16

    mySQL - Does Int(9.455.487) take more space than string(John) in mySQL?

  17. 17

    Graphs, vertices, STL lists: Why does list come out empty?

  18. 18

    Why does this code hang during an insert of stl list

  19. 19

    Graphs, vertices, STL lists: Why does list come out empty?

  20. 20

    Python - why is regular expression much more efficient than search in list?

  21. 21

    List View Does not show more than 10 Item

  22. 22

    Does '*(&x)' take more work than 'x'

  23. 23

    Does a subclass take more memory than a superclass

  24. 24

    Does a subclass take more memory than a superclass

  25. 25

    Why does a virtual box VM take up more space after I import it?

  26. 26

    Why does .NET List Sort() not take an explicitly declared delegate object?

  27. 27

    Why does the delegate take a parameter when no parameter list is specified?

  28. 28

    Why does .NET List Sort() not take an explicitly declared delegate object?

  29. 29

    Implementation of non increasing list with STL C++

HotTag

Archive