管理派生对象指针集合的最佳方法

时间:2012-05-24 03:09:29

标签: c++ oop c++11

我是来自c#的c ++的新手。以下代码无效,我不确定它需要什么。任何洞察力都可以帮助我理解它为什么不起作用以及它应该具有哪些适当的变化。

// GamePlayScreen derives from ScreenBase
std::unique_ptr<GameplayScreen> m_game(new GameplayScreen());

// MenuScreen derives from ScreenBase
std::unique_ptr<MenuScreen> m_menu(new MenuScreen());

// PauseScreen derives from ScreenBase
std::unique_ptr<PauseScreen> m_pause(new PauseScreen());        

std::vector<std::unique_ptr<ScreenBase>*> screens;

screens.push_back(&m_game); // this gets the error

我收到编译错误:

  

C2284“无法将参数1从'std :: unique_ptr&lt; _Ty&gt; *'转换为'std :: unique_ptr&lt; _Ty&gt; *&amp;&amp;'

如果我注释掉最后一行,它编译得很好。

基本上,我想要一个派生项的集合(或者更确切地说是指向它们的指针)。我已经尝试了各种方法'指向和/或参考'参数以及在vector<T>中建立T的各种方法,但解决方案使我望而却步。

5 个答案:

答案 0 :(得分:3)

这里没有编译器可以验证,但我相信你可以:

// GamePlayScreen derives from ScreenBase
std::shared_ptr<GameplayScreen> m_game(new GameplayScreen());

// MenuScreen derives from ScreenBase
std::shared_ptr<MenuScreen> m_menu(new MenuScreen());

// PauseScreen derives from ScreenBase
std::shared_ptr<PauseScreen> m_pause(new PauseScreen());        

std::vector<std::shared_ptr<ScreenBase>> screens;

screens.push_back( m_game );

就像@ cheers-and-hth-alf所说,你可能想要共享指针。

答案 1 :(得分:3)

我正在阅读很多内容:

  

...你可能想要shared_ptrs ......

我会鼓励人们在不确定时默认为unique_ptr。在没有内存所有权设计的情况下放下shared_ptr正是导致循环内存泄漏的原因。

是的,您也可以使用unique_ptr创建循环内存泄漏。然而,我的经验是,当使用unique_ptr时,它鼓励设计师了解谁拥有设计演变时的内容,使循环内存泄漏的可能性降低,并且在发生时更容易调试。

如果在此设计过程中,设计人员发现实际需要共享所有权语义,那么无论如何都要达到shared_ptr(也可能weak_ptr来打破这些周期。)

最后,尽快将原始指针绑定到智能指针。以下是OP问题的可编辑草图,它遵循最佳实践:

#include <type_traits>
#include <utility>
#include <memory>
#include <vector>

// A general purpose factory function for unique_ptrs
// Feel free to make this factory function more specific to your domain
template <class T, class ...Args>
typename std::enable_if
<
    !std::is_array<T>::value,
    std::unique_ptr<T>
>::type
make_ScreenParts(Args&& ...args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

// Your class hierarchy
struct ScreenBase
{
    // Don't forget to make your destructors virtual
    virtual ~ScreenBase() = default;
};

// Future-proof your code with typedef's
// If / when you need to switch smart pointer types
//  or container types, you'll thank yourself
typedef std::unique_ptr<ScreenBase> ScreenPtr;
typedef std::vector<ScreenPtr> ScreenContainer;

struct GameplayScreen
    : public ScreenBase
{
};

struct MenuScreen
    : public ScreenBase
{
};

struct PauseScreen
    : public ScreenBase
{
};

int main()
{
    // raw pointers never exposed here...
    ScreenContainer screens;
    screens.push_back(make_ScreenParts<GameplayScreen>());
}

答案 2 :(得分:2)

尝试更改最后两行,如下所示:

std::vector<std::unique_ptr<ScreenBase>> screens;

screens.push_back(std::move(m_game));

我删除了星号,因为你可能想要一个unique_ptr的向量,而不是unique_ptr指针的向量。此外,unique_ptr顾名思义,意味着一次只有一个unique_ptr可以拥有所有权,因此您需要明确std::move来转让所有权。

答案 3 :(得分:1)

使用shared_ptr代替unique_ptr,因为您要从很多地方引用这些屏幕对象。

答案 4 :(得分:0)

听起来你想要管理具有特定类型的各种屏幕,但是还有另一个屏幕列表作为基本类型,这样你就可以在所有屏幕上进行某些操作而无需知道具体屏幕类型的详细信息。

我认为在这种情况下你只需要一个原始指针:

// GamePlayScreen derives from ScreenBase
std::unique_ptr<GameplayScreen> m_game(new GameplayScreen());

// MenuScreen derives from ScreenBase
std::unique_ptr<MenuScreen> m_menu(new MenuScreen());

// PauseScreen derives from ScreenBase
std::unique_ptr<PauseScreen> m_pause(new PauseScreen());        

std::vector<ScreenBase*> screens;

screens.push_back(&*m_game);

如果你破坏屏幕,你必须小心不要将指针悬挂在屏幕上。