首页 > 解决方案 > FIFO 释放订单的 RAII 等效项

问题描述

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
}

也就是说,我们将在释放odd插槽之前释放even插槽。虽然我可以在其中添加一个“重新排序”队列,但stream我想知道是否有一种“干净”的方式将 RAII 推广到这些情况。

标签: c++raii

解决方案


使用std::optional,以非常适中的最小开销为代价提供对构造的更多控制以及明确定义的销毁顺序。这正是您正在寻找的,在这里。

例如:

std::optional<stream_wslot> o_even;
std::optional<stream_wslot> o_odd;

o_odd.emplace(fifo);
o_even.emplace(fifo);

auto &even=*o_even;
auto &odd=*o_odd;

从这一点开始,现有代码使用odd并且even会发现很难区分。总计:odd首先构建,然后even构建。odd首先被销毁,离开此范围时,even第二个被销毁。相同的有效建造和销毁顺序。


推荐阅读