2

i write a stack class in c++ (shown below) but it is static and sure it uses lots of memory's. how can i make it dynamic so when ever it need it add some memory to the object and when ever i pop something the memory automatically delete?

template <class T>
class stack
{
private:
    T value[512];
    uint16_t length;
public:
    stack()
    {
        length=0;
    }

    stack(T _input)
    {
        value[0]=_input;
        length=1;
    }

    bool push(T _input)
    {
        if(length+1<512)
        {
            value[++length]=_input;
            return true;    
        }
        else
            return false;
    }

    T pop()
    {
        return value[length--];     
    }

    T peak()
    {
        return value[length];   
    }

    bool has_data()
    {
        return (length>0?true:false);
    }

};
Xeo
  • 129,499
  • 52
  • 291
  • 397
mefmef
  • 665
  • 2
  • 11
  • 23
  • 8
    Easy answer: Use `std::stack`. :P Real answer: Get a [good book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) and learn about `new` and dynamic memory allocation. – Xeo Dec 12 '11 at 13:27
  • i forgot to say : as i write the code on microprocessor i can not use standard library like std::stack – mefmef Dec 12 '11 at 13:28
  • 3
    What exactly prohibits you from using the standard library? – Xeo Dec 12 '11 at 13:29
  • But maybe you're µC supports new and delete as stated by Xeo – Sebastian Dec 12 '11 at 13:30
  • 1
    :) simple ,my compiler does not support it , beside as we are in lack of resources in microprocessor including the big library is not what we want. – mefmef Dec 12 '11 at 13:31
  • is the performance cost of lots of news/deletes also something you might not want? Ideally, if you know the max size of each stack instance, you would pass in 'int MaxSize' to the constructor, and new the value array to that size, rather than new/delete per push/pop – Hybrid Dec 12 '11 at 13:32
  • yes i know i should use new! but please guide me how can i do it in this particular class. – mefmef Dec 12 '11 at 13:34
  • 1
    isn't 'how do i use new' a basic 'go learn c++' type thing? – Hybrid Dec 12 '11 at 13:35
  • thank u hybrid would u please write me some code? – mefmef Dec 12 '11 at 13:35
  • yes it is! and because of that i need help :) – mefmef Dec 12 '11 at 13:36
  • 1
    A common misconception about the standard library: It is *not* a big library. The most parts are templates (the STL part) and as with all templates, only those you *use* are compiled in. You might also want to take a look at [STLport](http://www.stlport.org/product.html), which you can use if your compiler doesn't bring a standard library as-is. – Xeo Dec 12 '11 at 13:41
  • 1
    mefmef: the thing about the standard library is that if you use something like `-O2`, only what you use is imported and *inlined*. using `std::stack` will make about the same impact on performance as writing your own. – Daniel Dec 12 '11 at 13:42
  • Beside of that, to use new / delete just provide a constructor and a destructor. But beware, that you only should provide a destructor if you really need it, cause it's provided by default and should only be overwritten if you're using dynamic memory within your class. – Sebastian Dec 12 '11 at 13:43

3 Answers3

3

You could also use std::vector :

template <class T>
class stack{
private:
std::vector<T> vec;
public:
inline void push(T arg){vec.push_back(arg);};
inline T pop(){return vec.pop_back();};
};
  • Unfortunately the OP has said his compiler doesn't have the standard library so this won't work. – tenfour Dec 12 '11 at 14:53
3

You have to allocate it dynamically when the need arises. Something like this maybe:

#define STACK_INITIAL_ALLOC   32
#define STACK_CHUNK_ALLOC    32

template<typename T>
class Stack
{
public:
    Stack()
        : data(0), entries(0), allocated(0)
        { }

    Stack(const T &value)
        : data(0), entries(0), allocated(0)
        {
            push(input);
        }

    ~Stack()
        {
            if (data)
                delete [] data;
        }

    void push(const T &value)
        {
            if (entries == allocated)
                allocate();  // Allocate more memory

            data[entries++] = value;
        }

    T pop()
        {
            if (entries > 0)
            {
                shrink();
                return data[--entries];
            }
            else
                throw runtime_error("stack empty");
        }

    T &top()
        {
            if (entries > 0)
                return data[entries - 1];
            else
                throw runtime_error("stack empty");
        }

    // Return the number of entries in the stack
    size_t count() const
        {
            return entries;
        }

private:
    T      *data;      // The actual stack
    size_t  entries;   // Number of entries in stack
    size_t  allocated; // Allocated entries in stack

    void copy(T *from, T *to)
        {
            for (size_t i = 0; i < entries; i++)
                *to++ = *from++
        }

    void allocate()
        {
            if (data == 0)
            {
                allocated = STACK_INITIAL_ALLOC;
                data = new T[allocated];
            }
            else
            {
                // We need to allocate more memory

                size_t new_allocated = allocated + STACK_CHUNK_ALLOC;
                T *new_data = new T[new_allocated];

                // Copy from old stack to new stack
                copy(data, new_data);

                // Delete the old data
                delete [] data;

                allocated = new_allocated;
                data = new_data;
            }
        }

    // Shrink the stack, if lots of it is unused
    void shrink()
        {
            // The limit which the number of entries must be lower than
            size_t shrink_limit = allocated - STACK_CHUNK_ALLOC * 2;

            // Do not shrink if we will get lower than the initial allocation (shrink_limit > STACK_INITIAL_ALLOC)
            if (shrink_limit > STACK_INITIAL_ALLOC && entries < shrink_limit)
            {
                // We can shrink the allocated memory a little
                size_t new_allocated = allocated - STACK_CHUNK_ALLOC;

                T *new_data = new T[new_size];

                copy(data, new_data);

                delete [] data;

                data = new_data;
                allocated = new_allocated;
            }
        }
};

Also a small disclaimer, this code was written straight into the browser. It's not tested, but should work in principle... :)

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
0

Any array like structure will be expensive to grow and shrink (T has to be copy constructible) and all the existing Ts have to be moved. If you find that you are doing lots of pushing/popping and you need to keep memory usage low, try using a linked list internally. It only has to be singly linked.

Here is a sketch:

template <class T>
class stack
{
  struct Node
  {
    T data;
    Node* next;
  };
public:

  // methods

private:
  Node *head;
};

Now, to push something on the stack, construct a Node with the T, set it's next pointer to current head, and the head to the Node pointer. Popping involves taking next from the head and setting that to the head.

Of course you need to manage the memory correctly on destruction etc.

EDIT: ah it appears that my assumption that you may know the basics of C++ is incorrect, I assumed you did as you are using a template. In this case - ignore this answer till you've learned the basics!

Nim
  • 33,299
  • 2
  • 62
  • 101
  • whats wrong with you people ? because that my c++ foundation is poor , i can not ask question?:( – mefmef Dec 12 '11 at 13:42
  • I'm sorry, but this is bad advice. A vector outperforms a list if correctly implemented. The point is that a list has to `new` and `delete` every time you manipulate it and has the tendency that its items are lying around all the memory (data-locality gone!). If you have a vector that grows and shrinks exponentially, you will at worst waste some memory (you are most likely wasting that memory for list-bookkeeping as well, if your items are small). – bitmask Dec 12 '11 at 13:44
  • 2
    @mefmef, there is nothing wrong with us, the concern is that if you don't understand the basics, there is little chance you will understand the answers. For example do you understand what I describe in my answer? If you don't you don't understand the basics - and I've wasted my time. I could write the code for you, but then you'll learn nothing - that for me is unacceptable. – Nim Dec 12 '11 at 13:45
  • it is my concern too , so just help me please do not judge my knowledge this site is not a class! – mefmef Dec 12 '11 at 13:47
  • 1
    @bitmask, a vector does outperform, iff your goal is to iterate through it - a stack does not have this functionality, hence I'd contend that locality is really not an issue. The point I was trying to make is that pushing/poping are the primary operations, and if these cause the vector to grow(and manually shrink) as necessary, that could be more expensive. – Nim Dec 12 '11 at 13:49
  • 1
    @mefmef, there is enough information in my answer and the comments around `new` and `delete` for anyone with a basic grasp of C++ to *work it out*. If you cannot, it means you need to really brush that up - we cannot help you much further.. – Nim Dec 12 '11 at 13:50
  • Nope, the astonishing thing is, it **still** outperforms the list -- we benchmarked it some time ago. The only valid reason to use a list is you do a **lot** of slicing; And in that case you're probably better of with a deque. – bitmask Dec 12 '11 at 13:53
  • @bitmask - I guess the heap allocation overhead is higher in that case than the copy construction (with placement), unfair really.. ;) If you want the performance, then use a free list too - I'd like to see how that compares... – Nim Dec 12 '11 at 13:55
  • Straightforward. You have a couple of parameters though: Item size, number of operations, copy construction overhead. You have to toy around with them to find the point at which one of the containers wins over the other. If memory serves me, it was really hard to find parameters such that the list wins (they were not overly convincing, but it's already some time ago that we did this, so forgive me if I don't remember any numbers). But this should probably be a community wiki question :) – bitmask Dec 12 '11 at 14:00