在c ++ 11中强制转换std :: future或std :: shared_future

时间:2014-05-29 12:30:42

标签: c++11 casting future

这可能听起来很愚蠢,但C ++和C ++ 11在它可以达到的魔力方面让我感到惊讶。也许这太过分了,但我更愿意确认我的恐惧,而不是假设它们。

是否有可能以任何方式强制转换std :: future或std :: future_shared对象?

我发现如果我描述我遇到的具体问题通常会有所帮助。我本质上是异步加载一些音频和视频,虽然我已经开始使用std :: async,我发现它非常有用,但直到现在我还没有使用过期货。它本质上是从我身上学到的,期货似乎能很好地处理异常,我想让我的异步加载更加强大。我的糟糕程序偶尔会耗尽内存,但在异步调用启动之前,程序不会发生这种情况。解决内存问题完全是另一个问题,目前还不是一个可行的解决方案。

无论如何 - 我有两个独立的对象来处理音频(AudioLibrary)和视频(VideoLibrary)的加载,但由于它们共享许多共性,它们都从相同的基础对象(BaseLibrary)继承。

每个相应库返回的音频和视频都有自己的音频容器(AudioTrack)和视频(VideoTrack),它们也从公共对象(BaseTrack)继承。

我确定你可以看到它的发展方向。我想在BaseLibrary中进行一些常规异常处理,它将具有一些虚拟函数,如loadMedia。这些将被派生库覆盖。这样麻烦就开始了。我读到指针对象(如unique_ptr或shared_ptr)不能协变,所以只创建一个虚拟方法并不能解决它。

然而,我希望通过虚拟功能,我仍然可以以某种方式达到我想要的效果。

实现以下内容的BaseLibrary:

std::shared_future<BaseTrack> BaseLibrary::loadMedia()
std::shared_future<BaseTrack> BaseLibrary::loadMediaHelper()

然后AudioLibrary将实现

std::shared_future<AudioTrack> AudioLibrary::loadAudio()

此函数使用BaseLibrary中的函数但返回其自己的特定类型的AudioTrack,而不是BaseTrack。

这一切都可能吗?

更新1:

感谢评论和回答,我看到了如何实现我的目标,但我还有一些未解决的问题。我认为通过非常明确地解决这些问题会更容易。我实际上正在使用shared_ptrs,因为许多对象正在使用加载的音频和视频,所以我有以下类型的defs:

typedef std::shared_ptr<BaseTrack> BaseTrackPtr;
typedef std::shared_ptr<AudioTrack> AudioTrackPtr;

AudioTrack当然继承自BaseTrack。根据给定的建议,我有一个可编译(缩写)的代码结构,对于BaseLibrary如下:

class BaseLibrary {
  virtual std::shared_future<BaseTrackPtr> loadMedia();
  virtual std::shared_future<BaseTrackPtr> loadMediaHelper() = 0;
}

std::shared_future<BaseTrackPtr> BaseLibrary::loadMedia()
{
// Place code to catch exceptions coming through the std::future here.
// Call the loadMediaHelper via async - loadMediaHelper is overwritten in the inherited libraries.
}

AudioLibrary:

class AudioLibrary : public BaseLibrary {
public:
  virtual std::shared_future<AudioTrackPtr> loadAudio();
protected:
  virtual std::shared_future<BaseTrackPtr> loadMediaHelper();
}

std::shared_future<AudioTrackPtr> AudioLibrary::loadAudio()
{
  std::shared_future<BaseTrackPtr> futureBaseTrackPtr = loadMedia();
  return std::async( std::launch::deferred, [=]() {
    return AudioTrackPtr( std::static_pointer_cast<AudioTrack>( futureBaseTrackPtr.get() ) );
} );
}

std::shared_future<BaseTrackPtr> AudioLibrary::loadMediaHelper()
{
  // Place specific audio loading code here
}

这种结构允许我在一个地方捕获任何视频/音频加载异常,并且还返回正确的音频/视频对象而不是需要重新制作的基础对象。

我目前的两个问题如下:

  • 最好让BaseLibrary中的loadMedia中的异步调用为std :: launch :: deferred,然后让loadAudio(或loadVideo)中的异步调用为std :: launch :: async ?我基本上希望立即开始加载,但也可以等待外部异步调用执行...?这有意义吗?
  • 最后,这真是难看吗?我的一部分感觉就像我正确地利用了C ++ 11提供的所有优点,shared_ptr&,期货等等。但是我对未来也很陌生......所以我不知道在共同的未来中共用一个指针是不是很奇怪?

1 个答案:

答案 0 :(得分:2)

所以你有类似的东西:

class BaseLibrary
{
public:
    virtual ~BaseLibrary() {}
    virtual std::shared_future<std::unique_ptr<BaseTrack>> loadMedia() = 0;
};

class AudioLibrary : public BaseLibrary
{
public:
    std::shared_future<AudioTrack> loadAudio();
    std::shared_future<std::unique_ptr<BaseTrack>> loadMedia() override;
};

所以你可以像这样实现loadMedia()

std::shared_future<std::unique_ptr<BaseTrack>> AudioLibrary::loadMedia()
{
    auto futureAudioTrack = loadAudio();

    return std::async(std::launch::deferred,
        [=]{
            std::unique_ptr<BaseTrack> res =
                make_unique<AudioTrack>(futureAudioTrack.get());
            return res;
        });
}