2012-05-24 2 views
3

C#에서 C++을 처음 사용했습니다. 다음 코드는 작동하지 않으며 필요한 코드가 무엇인지 잘 모르겠습니다. 그것이 작동하지 않는 이유와 적절한 변화가 무엇인지 이해할 수 있도록하는 통찰력은 인정 될 것입니다. 내가 마지막 줄을 주석 경우파생 된 개체에 대한 포인터 컬렉션을 관리하는 가장 좋은 방법

C2284 "cannot convert parameter 1 from 'std::unique_ptr<_Ty> *' to 'std::unique_ptr<_Ty> *&&'

, 그것은 잘 컴파일 :

// 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 

나는 오류가 컴파일 얻을.

기본적으로 나는 파생 된 항목의 모음 (또는 그 대신 포인터)을 갖고 싶습니다. 나는 '가리키고 및/또는 참조하는'다양한 방법을 사용하여 매개 변수와 다양한 방법으로 T를 설정하는 시도했습니다 vector<T>하지만 솔루션은 나를 eludes.

+1

@JesseGood 원하는 유형을 얻는 방법에 대한 해답을 가지고 : 다음은 모범 사례를 다음과 영업 이익의 문제에 대한 컴파일 가능한 스케치입니다 포인터가 당신의 목표입니다. @Alf는 대부분 shared_ptr을 사용하는 것이 좋습니다. 이 기사는 관심의 대상 일 수 있습니다 : http://hostilefork.com/2009/07/10/smart-pointer-casting-study/ – HostileFork

답변

3

나는 많이 읽고 있어요. shared_ptr을 메모리 소유권 디자인없이 사용하면주기적인 메모리 누수가 발생합니다.

예, unique_ptr도 주기적 메모리 누출을 만들 수 있습니다. 그러나 내 경험에 의하면 unique_ptr을 사용하면 설계자가 누가 디자인을 발전 시켰는지 이해하고 주기적 메모리 누수 가능성을 낮추며 오류가 발생할 때 쉽게 디버깅 할 수 있습니다.

그리고이 설계 프로세스 중에 설계자가 실제로 공유 소유권 의미론이 필요하다는 것을 발견하면 shared_ptr (아마도 해당주기를 깨기 위해 weak_ptr)까지 도달해야합니다.

마지막으로 가능한 빨리 생 포인터를 스마트 포인터에 바인딩하십시오. **이 전송-의 소유권 고유의를 맡길 경우 **,

#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>()); 
} 
+0

이 입력 해 주셔서 감사합니다. 경험이 부족하고 지식이 부족하기는하지만 필자가 읽은 대부분은 잘 작성된 C++ 코드가 원시 포인터를 더 이상 거의 사용하지 않는다는 것을 알려주며 이것이 사용자가 확증하는 것처럼 보입니다. 코드 스 니펫에 감사 드리며 일부 이해를 얻었지만 "... args"섹션에서 컴파일 할 부분을 찾지 못했지만 전달하는 점을 인식 할 수 있습니다. 감사합니다. –

+0

@SteveH : 컴파일러가 아직 가변적 인 템플릿을 구현하지 않았을 수 있습니다. 만약 그렇다면 위의 내용은 누출없이 컴파일되고 작동해야합니다. 이 경우, make_ScreenParts 오버로드를 여러 개 구현할 수 있습니다 : 하나는 0 개의 인수를 취합니다 -이 예에서 사용 된 것은 하나의 인수를 취하고 하나는 두 개의 인수를 취하는 것입니다. 일반적으로 다음과 같이 사용합니다 :'make_ScreenParts (arg1, arg2, arg3)', 여기서'GameplayScreen'은'arg1','arg2','arg3'을 취하는 생성자를 가지고 있습니다. –

+0

. args를 제거하기 위해이를 단순화하여 컴파일 할 수있었습니다. 나는 그들을 필요로 할 때 밖으로 일할 것이다. 그러나 컴파일러가 불평하지 않게하려면 ScreenBase::~ScreenBase(){};에 대한 정의를 추가해야했습니다. 나는 Scott Meyers의 저서를 가지고 있으며 가상 소멸자에 대한 이유를 지금도 알고 있습니다. 감사! –

1

unique_ptr 대신 shared_ptr을 사용하십시오. 여러 장소에서 화면 개체를 참조 할 것이므로 사용하십시오. 다음과 같이 마지막 두 줄을 변경

+0

답변 해 주셔서 감사합니다. 그러나 'unique-ptr'을 'shared_pter'로 바꾸면 문제가 계속 발생합니다. 같은 컴파일 오류. –

+4

@ 스티브 : 미안, 당신의 벡터에 대한 선언문을 보지 못했지만 이제는 그것을 볼 수 있습니다. 그것을 스마트 포인터에 대한 원시 포인터의 벡터로 만들지 마십시오. 그것을 스마트 포인터의 벡터로 만든다. –

+0

맞아요,하지만 다른 실패 코드가 비슷합니다 : 오류 C2664 : 'void std :: vector <_Ty> :: push_back (std :: shared_ptr * &&)': 매개 변수 1을 'std :: shared_ptr <_Ty> * 'to'std :: shared_ptr <_Ty> * && ' –

2

봅니다 : 당신은 아마, unique_ptrunique_ptr에 대한 포인터의 아닌 벡터를 벡터를 원했기 때문에

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

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

나는 별표를 제거했습니다. 또한 이름이 의미하는대로 unique_ptr은 한 번에 하나의 unique_ptr 소유권을 가질 수 있음을 의미하므로 소유권을 이전하려면 명시 적으로 std::move해야합니다.

+1

'm_game '과 같은 이름은 멤버 변수를 나타냅니다. 포인터가 멤버 변수 밖으로 이동한다는 것은 의문의 여지가 있습니다. –

+0

@ Cheersandhth.-Alf : 사실입니다. 그러나 목적이 무엇인지는 분명하지 않습니다. –

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); 

:

나는이 경우에 당신은 단지 원시 포인터를 원하는 생각합니다.

+0

이 작업은 컴파일되지만 화면 [0] -> 기본 클래스 항목에만 액세스합니다. 파생 된 클래스 항목에도 액세스하려고합니다. 내가 어떻게 그걸 할거야? –

+0

@SteveH : 기본 (스마트 또는 원시) 포인터를 통해 액세스하려는 각 멤버 함수에 대해 기본에는 * virtual * 멤버 함수가 있어야합니다. 그런 다음 컴파일러는 해당 멤버 함수의 * 파생 * 버전이 호출되는지 확인합니다. 이렇게 회원 데이터를 가상으로 만들 수는 없습니다. 그러나 파생 된 멤버 멤버 데이터에만 액세스하는 가상 멤버 함수를 기반에 작성할 수 있습니다. 이 경우 기본 가상 멤버 접근자는 순수 가상 ('= 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); 

@처럼 환호 앤 HTH-ALF 당신은 아마 공유 포인터를 원했다. 나는이 때 확실 unique_ptr에 기본값으로 사람들을 격려 할

...you probably want shared_ptrs...

:

관련 문제