1

我有一个队列的实现,类似于template <typename T> queue<T>a struct QueueItem { T data;},并且我有一个单独的库,用于计算数据在不同位置的传递(包括通过这个队列从一个生产者线程到消费者线程)。为了做到这一点,我将该计时库中的代码插入到队列的推送和弹出函数中,这样当他们分配 a 时,BufferItem.data他们还分配了一个额外的成员,我添加的类型void*为该库中的一些计时元数据。即曾经是这样的:

void push(T t)
{
  QueueItem i;
  i.data = t;
  //insert i into queue
}

变成了

void push(T t)
{
  QueueItem i;
  i.data = t;

  void* fox = timinglib.getMetadata();
  i.timingInfo = fox;
  //insert i into queue
}

QueueItem 从

struct QueueItem
{
 T data;
}

struct QueueItem
{
  T data;
  void* timingInfo;
}

然而,我想要实现的是,当时序库未激活时,能够换出后一个结构以支持更轻量的结构。就像是:

if timingLib.isInactive()
 ;//use the smaller struct QueueItem
else
 ;//use the larger struct QueueItem

尽可能便宜。什么是这样做的好方法?

4

2 回答 2

1

显然,您不能同时拥有一个既大又小的结构,因此您将不得不查看某种形式的继承或指针/引用或联合。

如果 T 中有可能被您的时间信息占用的“备用”数据,联合将是您的理想选择。如果不是,那么它将和原版一样“沉重”。

使用继承也可能和原来的一样大,因为它会在其中添加一个 vtable,这会过多地填充它。

因此,下一个选项是仅存储一个指针,并将该指针指向您要存储的数据,无论是数据还是数据+计时。这种模式被称为“元”——公共数据与被操作的对象分开存储。这可能是您正在寻找的(取决于时间信息元数据是什么)。

另一种更复杂的替代方法是让 2 个队列保持同步。您将数据存储在一个中,另一个存储相关的时间信息(如果启用)。如果未启用,则忽略第二个队列。这样做的问题是确保两者保持同步,但这是一个组织问题,而不是技术挑战。也许在内部创建一个包含 2 个真实队列的新 Queue 类。

于 2012-07-10T16:24:28.343 回答
1

我将首先确认我的假设,即这需要作为运行时选择,并且您不能只构建两个启用/禁用时间的不同二进制文件。这种方法尽可能多地消除任何方法的开销。

所以现在让我们假设我们想要不同的运行时行为。需要有运行时决策,所以有几个选项。如果您可以摆脱多态性的(相对较小的)成本,那么您可以使您的队列多态并在启动时创建适当的实例,然后push例如它会或不会添加额外的数据。

但是,如果这不是一个选项,我相信您可以使用模板来帮助完成您的任务,尽管可能会有一些前期工作,并且可能会通过额外的代码增加二进制文件的大小。

您从一个模板开始,为课程添加时间:

template <typename Timee>
struct Timed : public Timee
{
    void* timingInfo;
};

然后一个定时的 QueueItem 看起来像:

Timed<QueueItem> timed_item;

对于任何不关心时间的东西,这个类看起来完全像一个QueueItem: 它会自动向上转换或切片到父级。如果一个方法需要知道计时信息,您要么创建一个知道要为 a 做什么的重载,要么进行Timed<T>运行时检查(对于“是否启用计时”标志)并向下转换为正确的类型。

接下来,您需要更改您的Queue实例化以了解它使用的是基础版本QueueItem还是Timed版本。例如,一个可能机制的非常非常粗略的草图:

template <typename Element>
void run()
{
    Queue<Element> queue;

    queue.setup();
    queue.process();
}

int main()
{
    if(do_timing)
    {
        run<Timed<QueueItem> >();
    }
    else
    {
        run<QueueItem>();
    }

    return 0;
}

Queue当与项目一起使用时,您“可能”需要专门化,Timed除非获取元数据是无状态的,在这种情况下,Timed构造函数可以收集信息并在创建时自行填充。然后Queue保持不变并依赖于您使用的实例化。

于 2012-07-25T14:48:38.560 回答