3

我是来自 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<_Ty> *' 转换为 'std::unique_ptr<_Ty> *&&'

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

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

4

5 回答 5

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 所说,您可能需要共享指针。

于 2012-05-24T03:44:10.253 回答
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>());
}
于 2012-05-24T14:09:29.990 回答
2

尝试如下更改最后两行:

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

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

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

于 2012-05-24T03:20:15.820 回答
1

使用shared_ptr而不是unique_ptr,因为您将从许多地方引用这些屏幕对象。

于 2012-05-24T03:14:36.257 回答
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);

如果您破坏屏幕,您只需要小心不要让屏幕中的指针悬空。

于 2012-05-24T03:27:24.130 回答