2013-04-30 17 views
9

mam klasy PlayerInputComponent:Dlaczego wywołuje to konstruktor kopiowania, a nie konstruktor ruchu?

.h:

class PlayerInputComponent 
{ 
public: 
    PlayerInputComponent(PlayerMoveComponent& parentMoveComponent_, std::unique_ptr<IRawInputConverter> inputConverter_); 
    PlayerInputComponent(PlayerInputComponent&& moveFrom); 
    void update(); 

private: 
    std::unique_ptr<IRawInputConverter> inputConverter; 
    PlayerMoveComponent& parentMoveComponent; 
}; 
} 

.cpp:

PlayerInputComponent::PlayerInputComponent(PlayerMoveComponent& parentMoveComponent_, std::unique_ptr<IRawInputConverter> inputConverter_) : 
    parentMoveComponent(parentMoveComponent_), 
    inputConverter(std::move(inputConverter_)) 
{ 
} 

PlayerInputComponent::PlayerInputComponent(PlayerInputComponent&& moveFrom) : 
    parentMoveComponent(moveFrom.parentMoveComponent), 
    inputConverter(moveFrom.inputConverter.release()) 
{ 
} 

i klasy PlayerMoveComponen t, która zawiera człon PlayerInputComponent i inicjuje się za pomocą std::unique_ptr przekazany jako parametr. Jej konstruktor:

PlayerMoveComponent::PlayerMoveComponent(/* other parameters */ std::unique_ptr<IRawInputConverter> inputConverter) : 
    //other initializations 
    inputComponent(PlayerInputComponent(*this, std::move(inputConverter))) 
{ 
} 

zdefiniowałem własne konstruktora ruch dla klasy PlayerInputComponent od mojego zrozumienia jest to, że konstruktor domyślny ruch nie zostanie zbudowana dla klasy, która zawiera element odniesienia. W tym przypadku jednak wiem, że odniesienie pozostanie w zakresie czasu trwania obiektu PlayerInputComponent.

Odkąd jestem inicjowania PlayerMoveComponentinputComponent zmiennej s od tymczasowy, wierzę, jeden z dwóch następujących rzeczy ma się wydarzyć:

  1. PlayerInputComponent” s ruch konstruktor służy do zainicjowania elementu playerInputComponent zmienna.
  2. Ruch jest usuwany przez kompilator.

Jednakże Visual Studio 2012 pluje na to uwagę:

error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>' 
1>   with 
1>   [ 
1>    _Ty=SDLGame::IRawInputConverter 
1>   ] 
1>   c:\program files\microsoft visual studio 11.0\vc\include\memory(1447) : see declaration of 'std::unique_ptr<_Ty>::unique_ptr' 
1>   with 
1>   [ 
1>    _Ty=SDLGame::IRawInputConverter 
1>   ] 
1>   This diagnostic occurred in the compiler generated function 'PlayerInputComponent::PlayerInputComponent(const PlayerInputComponent &)' 

Dlaczego konstruktor kopia nazywany jest tutaj? Uczynienie z klasy PlayerInputComponent klasy parentMoveComponent zwykłą instancją ParentMoveComponent, a nie z odniesieniem, pozbywa się błędu, ale nie rozumiem, dlaczego - przetestowałem i zweryfikowałem, że obiekty budujące ruch z elementami referencyjnymi działają tak długo, jak długo dostarczasz własny konstruktor ruchu, więc o co chodzi?

+0

@MooingDuck: Nie widzę odpowiedzi na pytanie. Jestem pewien, że jest to błąd w MSVC. –

+1

@JesseDobra: [masz rację] (http://coliru.stacked-crooked.com/), źle odczytałem część kodu. To jest [Mój raport o błędzie] (https://connect.microsoft.com/VisualStudio/feedback/details/778513/msvc10-using-copy-constructor-zamiast-of-move): P –

+0

* Deklaracje * wyżej wymienionych klas, rozebrane, aby zawierały tylko odtwarzalne wyniki (co nie wydaje się być zbyt trudnym) byłoby miło również zobaczyć, w szczególności 'PlayerMoveComponent' – WhozCraig

Odpowiedz

1

Przepraszam z góry, jeśli to naprawdę nie odpowie na twoje pytanie, po prostu chcę zareagować na pozorną złożoność twojego problemu. Jeśli tak, to czy nie byłoby to tysiąc razy prostsze:

/********************  **********  ********************/ 

class C {}; 
class B; 



class A 
{ 
public: 

    A(): _b(nullptr), _c(nullptr) {} 
    A(B *b, C *c): _b(b), _c(c) {} 
    A(A&& a): _b(a._b), _c(a._c) {} 

private: 

    C *_c; 
    B *_b; 
}; 



class B 
{ 
public: 

    B(/* other parameters */ C *c): _a(A(this,c)) {} 

private: 

    A _a; 
}; 


    /********************  **********  ********************/ 


int main() 
{ 
    C c; 
    B b(&c); 
} 

a mimo to osiągnąć to samo? Nie mam nic przeciwko używaniu nowych funkcji w C++ 11, takich jak std::unique_ptr, ale IMHO, upewniając się, że wskaźnik nie może zostać usunięty z dwóch miejsc, nie powinno być kwestią sprawdzania w czasie wykonywania (chyba że w bardzo rzadkich przypadkach), ale kwestia projektu ... czyż nie?

+0

Naprawdę się z tobą zgadzam, ale myślę, że głównym powodem, dla którego nie wolno używać surowych wskazówek, jest posiadanie pewności co do tego, kto go używa. Na przykład w twoim kodzie mógłbym przekazać wskaźnik c do twojej klasy B, a po tym wywołaniu usunąć na niej! (BUM ... to się kiedyś zdarzy). Użycie unique_ptr, jak stwierdzono, zapobiegnie temu, ponieważ kontrola zostanie przekazana do nowej instancji B i nikt poza nią nie może go usunąć. –

+0

Ahn ... a przy okazji, nie wiem, czy unique_ptr robi jakąkolwiek kontrolę podczas dereferencji ... jeśli utworzysz całkiem nowy (nullptr) i spróbujesz uzyskać do niego dostęp, to zawiesi się jak każdy wskaźnik. Jest to przydatne, gdy chcesz upewnić się, kto jest właścicielem i musi to być JEDEN właściciel (unikatowy). –

+0

@JulioRaffaine Wielkie dzięki za te komentarze!:) To, co miałem na myśli, to dereferencja; jedyny powód, dla którego chcesz, aby 'unique_ptr' było, ponieważ nie chcesz, aby ktokolwiek inny miał do niego dostęp. AFA kasowanie jest zaniepokojony, zabawnie, myślę, że powinno być rzeczywiście prostsze, jeśli zamierzałeś użyć 'unique_ptr' i że ostatecznie tego nie robisz: jedyną klasą, która zawierała unikalne c-wskaźniki tutaj było A, więc logicznie A powinien usuń pamięć przydzieloną dla c w jej destruktorze i "unieważnij" ją, gdy jest po prostu kopiowana. – Sheljohn

1

Jeśli zainicjujesz nowy obiekt za pomocą =, konstruktor kopiowania zostanie domyślnie uruchomiony. Aby uruchomić konstruktor ruchu, musisz zmienić zachowanie operator= Możesz znaleźć przykład: here Mam nadzieję, że ci pomogłem.

Powiązane problemy