引用,向量,std :: vector :: at和易于使用的接口

时间:2014-01-17 19:39:40

标签: c++ vector reference

最近我一直在使用一些音频代码,虽然不需要领域经验来理解这个问题,但我认为这可能有助于实现我的意图。

我有一个带有std :: vector of Audio_channel对象的控制器对象。该向量中的每个音频通道都用于保持每个通道的状态(播放,不播放...)。我正在使用的一个特定库与回调一起使用,因此您播放声音,将频道标记为“正在播放”,并且在完成播放后,您可以将其标记为“空闲”。出于本示例的目的,我们假设Audio_channel :: play_something()存在并按预期执行:标记为播放并开始播放声音,等待声音完成时的回调。

无论如何,大多数时候你都可以通过控制器对象播放声音,如下所示:

int channel=0;
audio_controller.play_some_sound(channel); //It would really do something like this->channels.at(0).play_something();

当然,它会起作用,因为audio_controller确实拥有这些Audio_channels。

有时候你想要一个自己的频道并且会这样做:

Audio_channel c=audio_controller.get_me_this_channel(0); //This returns the channel by reference with vector.at(). Try and catch blocks are ommited. 
c.play_something();

虽然它会起作用(因为它包装了一个不知道这些抽象的库),但我知道这个Audio_channel是原始的副本,因此无法从控制器中查询(因为任何更改都不是没反映出来。

我总是可以去:

Audio_channel& c=audio_controller.get_me_this_channel(0);
c.play_something();

而这一次我得到了真正的交易,任何变化都反映在各处...事实上,从“调用代码”的角度来看,在那里强制引用可能是违反直觉的 - 特别是在没有错误发生的情况下编译器,因为不存在错误。总有一些指针,但我想把它们放在表面之下。我猜智能指针也是一个选项,但我再次希望尽可能接近原始代码。

您可以在这里看到我可能缺少的其他选项吗?我考虑将Audio_channel包装到其他做脏访问工作的东西并返回这个其他接口的副本......我会进入很多代码重定向和方法,只调用引用通道的方法但是...

如上所述,有什么我可能会失踪吗?我正在使用最近的gcc编译器,所以允许使用C ++ X11热门东西。非常感谢。

2 个答案:

答案 0 :(得分:1)

编译器不会发生任何错误,因为不存在错误

如果您想在此处输入错误,请更改Audio_channel的设计,您可以使用C ++ 11编写:

class Audio_channel
{
    Audio_channel( const Audio_channel& ) = delete;
    Audio_channel& operator=( const Audio_channel& ) = delete;
    ...
};
Audio_channel c=audio_controller.get_me_this_channel(0);

这将导致编译错误。现在调用代码被强制通过引用获取返回值。

如果你真的想要一个价值语义,就像你的答案所暗示的那样,你已经走上了正确的轨道。您正在将proxy pattern实施为音频频道的参考。类似的东西:

class Audio_channel_proxy
{
public:
    Audio_channel_proxy( Audio_channel& c ) : m_channel( c ) {}
    void play_something() { m_channel.play_something(); }
...
private:
    Audio_channel &m_channel;
}

默认情况下,我更喜欢第一种方法,强制引用很常见,自我记录并且易于实现。

第二种方法并不常见,但也不罕见。它有一个潜在的陷阱。特别是如果您使用Audio_channel重命名代理:它不是自我记录的。

Audio_channel c=audio_controller.get_me_this_channel(0);

此行表明频道的唯一所有权,因为它是按值复制的。但实际上它只是一个频道的别名,其他人也可以修改。所以你最好把它记录下来(我会从命名开始)。我想你已经注意到了。每当我看到这种方法时,至少有一个人弄错了,直到他吸取了教训,包括我。此外,您需要在代理中实现维护Audio_channel的接口。只是因为没有被迫写出参考的语法糖,它并不值得。

另一方面,如果您想要通过audio_controller或其他人直接访问它的通道(或至少识别)的不同行为,则代理具有实际值。但只有在需要的时候才开始。

答案 1 :(得分:0)

我会在这里回答,但我会对任何建议持开放态度,因为这个解决方案似乎是正确的,尽管不是最佳的。

我所做的是将Audio_channel转换为Audio_channel_nonpublic并将其保密为控制器。控制器现在返回一个围绕Audio_channel_nonpublic(恰当地命名为Audio_channel)的包装类,该类具有对原始引用的引用并正确获取副本。新的Audio_channel实现与Audio_channel_nonpublic相同的公共接口,并将每个调用转发给引用的对象。这样就不需要改变任何客户端代码了。

结果有效,但有很多前向声明和代码块,当我几个月后回到它们时可能会有点混乱......它记录时间!!。

感谢您的评论。