【问题标题】:Reallocate memory for both stack and heap pointer为堆栈和堆指针重新分配内存
【发布时间】:2019-10-23 08:37:30
【问题描述】:

我开发了一个阻塞队列类如下

class Blocking_queue
{
public:
    Blocking_queue();

    int put(void* elem, size_t elem_size);
    int take(void* event);

    unsigned int get_size();

private:

    typedef struct element
    {
        void* elem;
        size_t elem_size;
        struct element* next;
    }element_t;

    std::mutex m_lock;
    std::condition_variable m_condition;
    unsigned int m_size;
    element_t* m_head;
    element_t* m_tail;

};

我希望类尽可能通用,因此我使用了一个 void 指针,该指针在元素添加到队列时分配,从队列中删除时释放。

int Blocking_queue::take(void* event)
{
    element_t* new_head = NULL;
    int ret = 0;

    // Queue empty
    if(nullptr == m_head)
    {
        // Wait for an element to be added to the queue
        std::unique_lock<std::mutex> unique_lock(m_lock);
        m_condition.wait(unique_lock);
    }

    if(nullptr == realloc(event, m_head->elem_size))
    {
        ret = -1;
    }
    else
    {
        // Take element from queue
        memcpy(event, m_head->elem, m_head->elem_size);
        ret = m_head->elem_size;
        new_head = m_head->next;
        free(m_head->elem);
        free(m_head);
        m_head = new_head;
        if(nullptr == m_head)
        {
            m_tail = nullptr;
        }
        m_size -= 1;
    }
    return ret;
}

如果队列为空,take() 函数将在 m_condition 上等待,直到添加新元素。

在释放元素之前,必须提供指针event 来复制元素的内容。

为了确保给定的指针具有正确的大小来复制元素的内容,我重新分配了指针及其大小。

我遇到的问题是它不允许传递函数的语言环境变量,因为它是在堆栈上分配的。

所以如果我做这样的事情

void function()
{
    unsigned int event = 0;

    queue->take(&event);
}

我将在 realloc 上遇到 invalid old size 错误。

所以如果我传递一个空指针或一个堆分配的变量,它会工作,但如果我传递一个堆栈变量地址,它就不会。

有没有办法允许将堆栈变量地址传递给take()函数?

【问题讨论】:

  • 如果有什么伤害,不要这样做。你的设计完全错误。
  • typedef struct element -- 在 C++ 中不需要typedef struct。您只需要struct element。其次,我希望类尽可能通用——如果元素是非 POD 类型,例如std::string,你的类将如何工作?使用mallocrealloc 等将不起作用。这看起来像是使用C 构造的尝试,期望C 的工作方式与C++ w.r.t 相同。动态创建实例并处理这些实例。在 C++ 中通过使用模板来实现“通用”。
  • 玩得开心spurious wakeups

标签: c++ heap-memory stack-memory memory-reallocation


【解决方案1】:

有没有办法允许将堆栈变量地址传递给 take() 功能?

简短的回答是否定的。 malloc()/free()/realloc()只能使用堆分配的内存;它们不适用于堆栈分配的内存。

至于如何解决这个问题,我认为需要重新设计。我的第一个建议是尽可能远离(void *)——void-pointers 非常不安全且难以正确使用,因为编译器对它们指向的内容一无所知,因此在程序员执行某些操作时不会产生错误错误地;这会导致很多运行时问题。它们更像是一种 C 语言结构,在 C++ 中仍受支持以提供 C 兼容性,但 C++ 有更好、更安全的方法来做同样的事情。

特别是,如果您的队列中的所有数据元素都应该是相同的类型,那么显而易见的做法是将您的 Blocking_queue 类模板化为该类型作为模板参数;然后用户可以指定例如Blocking_queue&lt;MyFavoriteDataType&gt; 并使用他喜欢的任何类型,并提供易于使用的按值语义(类似于 std::vector 和朋友提供的语义)

如果你想允许混合不同类型的数据元素,那么最好的办法还是上面的,但是为对象定义一个公共基类,然后你可以实例化一个Blocking_queue&lt;std::shared_ptr&lt;TheCommonBaseClass&gt; &gt;对象将接受指向该基类的任何子类的任何堆分配对象的共享指针。 (如果您确实需要将共享指针传递给堆栈分配的对象,您可以通过为共享指针定义自定义分配器来做到这一点,但请注意,这样做会打开对象生命周期不匹配问题的大门,因为堆栈对象可能在它们从队列中移除之前被销毁)

【讨论】:

    猜你喜欢
    • 2012-09-16
    • 2021-09-01
    • 2020-09-02
    • 2011-12-01
    • 2019-05-17
    • 2011-10-09
    • 2017-09-24
    • 2011-05-28
    相关资源
    最近更新 更多