在 c++11 中转换 std::future 或 std::shared_future
Posted
技术标签:
【中文标题】在 c++11 中转换 std::future 或 std::shared_future【英文标题】:Casting std::future or std::shared_future in c++11 【发布时间】:2014-05-29 12:30:41 【问题描述】:这听起来可能很愚蠢,但 C++ 和 C++11 之前的神奇之处让我感到惊讶。也许这太过分了,但我更愿意确认我的恐惧而不是假设它们。
是否可以以任何方式强制转换 std::future 或 std::future_shared 对象?
我发现如果我描述我遇到的具体问题通常会有所帮助。我实际上是在异步加载一些音频和视频,虽然我已经开始使用我觉得非常有用的 std::async,但直到现在我还没有使用过 futures。它本质上源于我了解到 futures 似乎可以很好地处理异常,并且我想让我的异步加载更加健壮。我的糟糕程序偶尔会耗尽内存,但在启动异步调用之前,程序不会发生这种情况。解决内存问题完全是另一个问题,目前还不是可行的解决方案。
无论如何 - 我有两个单独的对象来处理音频 (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.
还有音频库:
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's,futures 等等。但我对期货也很陌生,所以......我不知道将共享指针放在共享未来是否......很奇怪?【问题讨论】:
与creating-a-future-from-intermediate-futures相关 您可以在 Load 方法中公开策略以获得所需的灵活性(在***别只能使用一个std::launch::async
)。
我认为将智能指针放在future
中没有任何问题。
【参考方案1】:
所以你有类似的东西:
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;
);
【讨论】:
以上是关于在 c++11 中转换 std::future 或 std::shared_future的主要内容,如果未能解决你的问题,请参考以下文章
[C++11 多线程异步] --- std::promise/std::future
[C++11 多线程异步] --- std::promise/std::future
[C++11 多线程异步] --- std::promise/std::future