【问题标题】:how to make my stack class dynamic如何使我的堆栈类动态化
【发布时间】:2012-01-18 11:44:31
【问题描述】:

我在 C++ 中编写了一个堆栈类(如下所示),但它是静态的,并且确保它使用大量内存。我怎样才能使它动态化,以便在需要时向对象添加一些内存,并且当我弹出某些内容时,内存会自动删除?

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);
    }

};

【问题讨论】:

  • 简单回答:使用std::stack。 :P 真正的答案:获取good book 并了解new 和动态内存分配。
  • 究竟是什么禁止你使用标准库?
  • :) 很简单,我的编译器不支持它,而且我们在微处理器中缺乏资源,包括大库不是我们想要的。
  • “我如何使用新的”不是基本的“去学习 C++”类型的东西吗?
  • 对标准库的一个常见误解:它不是一个大库。大多数部分是模板(STL 部分),与所有模板一样,只有您使用的模板会被编译。您可能还想看看STLport,如果您的编译器没有按原样提供标准库。

标签: c++ dynamic stack


【解决方案1】:

您必须在需要时动态分配它。可能是这样的:

#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;
            }
        }
};

还有一个小小的免责声明,这段代码是直接写入浏览器的。它没有经过测试,但原则上应该可以工作...... :)

【讨论】:

  • @tenfour 添加了我自己的复制,它复制对象而不是内存
【解决方案2】:

你也可以使用 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();};
};

【讨论】:

  • 不幸的是,OP 说他的编译器没有标准库,所以这不起作用。
【解决方案3】:

任何类似数组的结构的增长和收缩都会很昂贵(T 必须是可复制构造的)并且所有现有的Ts 都必须移动。如果您发现您正在执行大量推送/弹出操作并且需要保持较低的内存使用率,请尝试在内部使用链表。它只需要单独链接。

这是一个草图:

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

  // methods

private:
  Node *head;
};

现在,要将某些内容压入堆栈,请使用T 构造一个Node,将其下一个指针设置为当前head,并将head 设置为Node 指针。弹出涉及从head 获取next 并将其设置为head

当然,您需要在销毁等时正确管理内存。

编辑:啊,看来我假设您可能知道 C++ 的基础知识是不正确的,我假设您在使用模板时这样做了。在这种情况下 - 在您了解基础知识之前忽略此答案!

【讨论】:

  • 你们怎么了?因为我的c++基础很差,我不能问问题吗?:(
  • 很抱歉,这是个糟糕的建议。如果正确实施,向量会胜过列表。关键是,每次操作列表时,列表都必须newdelete,并且它的项目倾向于遍布所有内存(数据局部性消失了!)。如果你有一个呈指数增长和缩小的向量,你最多会浪费一些内存(如果你的项目很小,你很可能也会将这些内存浪费在列表簿记上)。
  • @mefmef,我们没有错,担心的是,如果您不了解基础知识,您将很难理解答案。例如,您了解我在回答中描述的内容吗?如果你不了解,那么你就不了解基础知识——我浪费了我的时间。我可以为你写代码,但你什么也学不到——这对我来说是不可接受的。
  • @bitmask,如果您的目标是遍历它,向量的性能确实优于它 - 堆栈没有此功能,因此我认为局部性确实不是问题。我试图说明的一点是,推送/弹出是主要操作,如果这些导致向量根据需要增长(并手动缩小),那可能会更昂贵。
  • @mefmef,在我的回答和newdelete 周围的cmets 中有足够的信息供任何对C++ 有基本了解的人解决。如果你不能,这意味着你需要真正刷一下 - 我们无法为你提供更多帮助..
猜你喜欢
  • 2014-02-26
  • 2015-06-11
  • 1970-01-01
  • 1970-01-01
  • 2012-12-20
  • 2019-06-19
  • 2016-04-18
  • 2011-07-12
  • 1970-01-01
相关资源
最近更新 更多