Ark*_*aik 0 c++ heap-memory stack-memory memory-reallocation
我开发了如下的阻塞队列类
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;
};
Run Code Online (Sandbox Code Playgroud)
我希望该类尽可能通用,因此我正在使用一个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;
}
Run Code Online (Sandbox Code Playgroud)
如果队列为空,take()函数将等待m_condition直到添加新元素。
event在释放元素之前,必须提供一个指针来复制元素的内容。
为了确保给定的指针具有正确的大小以复制元素的内容,我将其大小重新分配给指针。
我的问题是它不允许传递函数的语言环境变量,因为它是在堆栈上分配的。
所以如果我做这样的事情
void function()
{
unsigned int event = 0;
queue->take(&event);
}
Run Code Online (Sandbox Code Playgroud)
我invalid old size在重新分配时会出错。
因此,如果我传递一个空指针或一个堆分配的变量,它将起作用,但是如果传递一个堆栈变量地址,它将不会起作用。
有没有一种方法可以将堆栈变量地址传递给take()函数?
有没有一种方法可以将堆栈变量地址传递给take()函数?
最简洁的答案是不。 malloc()/ free()/ realloc()只能与堆分配存储器工作; 它们将不适用于堆栈分配的内存。
至于您可能如何解决此问题,我认为将需要重新设计。我的第一个建议是尽可能远离(void *)-无效指针是极其不安全的,并且很难正确使用,因为编译器对其所指向的内容一无所知,因此当程序员错误地执行某些操作时,它们不会产生错误。这会导致很多运行时问题。它们更像是一种C语言构造,C ++仍支持该语言以提供C兼容性,但是C ++具有更好,更安全的方式来执行相同的操作。
特别是,如果期望队列中的所有数据元素都是相同的类型,那么显而易见的事情就是将以该类型为模板参数的Blocking_queue类作为模板参数;然后用户可以指定例如Blocking_queue<MyFavoriteDataType>并使用他喜欢的任何类型,并提供易于使用的按值语义(类似于例如eg std::vector和朋友提供的语义)
如果您想允许混合使用不同类型的数据元素,那么最好的方法还是上面的操作,但是为对象定义一个通用的基类,然后可以实例化一个Blocking_queue<std::shared_ptr<TheCommonBaseClass> >对象,该对象将接受共享指针该基类的任何子类的任何堆分配对象。(如果确实需要将共享指针传递给堆栈分配的对象,则可以通过为共享指针定义自定义分配器来实现,但是请注意,这样做会打开对象-寿命-不匹配问题的大门,因为堆栈对象在将其从队列中删除之前可能已被销毁)