【发布时间】:2020-06-09 21:55:55
【问题描述】:
RAII 非常舒适,我很难为必须按照它们被获取的顺序 (FIFO) 释放的资源提供等效的设计,而不是按照 RAII 自然产生的相反顺序 (Stack)。
在我的具体情况下,我有一个stream 类如下:
template<typename T>
class stream {
...
public:
// Producer API
T& write_acquire(); // This acquires a storage element and will "block"
// until a slot is available in the underlying resource
void write_release(&T); // This releases the storage element, transferring the data to a consumer
// Consumer API
T& read_acquire(); // This acquires a storage element and will "block"
// until a slot has been write_release
void read_release(&T); // This releases the storage element making it available
// for a potential future write_acquire
};
我正在考虑提供一个 RAII 样式的助手:
template<typename T>
class stream_wslot {
stream<T> &s;
T &slot;
public:
stream_wslot(stream<T> &s) : s{s}, slot{s.write_acquire()} {}
~stream_wslot() { s.write_release(slot); }
operator T&() { return slot; }
T& operator=(T &val) { return slot = val; }
};
但问题是以下用法将无法正常运行:
void test(stream<float> &fifo) {
stream_wslot even(fifo);
stream_wslot odd(fifo);
... first ...
... second ...
// releases odd !!!
// releases even
}
也就是说,我们将在释放even 插槽之前释放odd 插槽。虽然我可以在stream 中添加一个“重新排序”队列,但我想知道是否有一种“干净”的方式将 RAII 推广到这些情况。
【问题讨论】:
-
不要让调用者直接访问
T,给他们一个shared_ptr<Node<T>>,每个节点都有一个shared_ptr指向列表中的下一个节点。然后,当第二个指针被销毁时,Node 将保持 T 处于活动状态,直到第一个指针也被销毁。哦等等,实际的破坏仍然以错误的顺序发生。该死。 -
不能使用
std::queue吗?从我所看到的情况来看,它会按照自身销毁时输入的顺序销毁所包含的元素。 -
这很微妙,但我认为您的类型违反了“资源”的隐含合同。因此,您不应该将其视为资源(相反,考虑将整个事务包装到它自己的资源中,这实际上是建议使用队列的评论和答案正在做的事情)。跨度>
-
匿名者:你有没有尝试过你在答案中得到的任何建议?
-
@TedLyngmo 我做到了,您基于队列的解决方案很好(从可读性的角度来看),但我的情况是嵌入式硬件,因此动态分配很昂贵/不可用。