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

次のように最後の2行を変更してみてください。

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

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

アスタリスクを削除したのはunique_ptr、へのポインタのベクトルではなく、のベクトルが必要だったためですunique_ptr。また、unique_ptrその名前が示すように、一度に所有権を持つことができるのは1つだけであることを意味する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 に答える