• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Kopiowanie głębokie obiektu ( wykonywanie kopii inteligentnego wslaźnika std::unique_ptr )

Object Storage Arubacloud
0 głosów
402 wizyt
pytanie zadane 31 marca 2019 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)
zamknięte 3 kwietnia 2019 przez Jakub 0

Witam, początkowo miałem taki kod:

//-----------------------------------------------------------------------------------------------

	sf::Vector2f windowSize = window.mapPixelToCoords(sf::Vector2i(window.getSize().x, window.getSize().y));

	int numberOfEntities = 80;
	sf::Vector2f entityGenerationPoint = windowSize / 2.f; 
	float entitySeparationDistance = 30.f;
	float entitiesSpeed = 100.f;
	float entitiesNeighborhoodZone = 300.f;
	float timeToStartFlocking = 1.f;

	std::list<Entity> mainFlockingEntityList;
	for (int i = 0; i < numberOfEntities; ++i) {
		mainFlockingEntityList.emplace_back(std::make_unique<ClassicFishShape>(
			ClassicFishShape(sf::Vector2f(20.f, 30.f), std::string("fish.png"), SMALL_FISH)), AdditionalMatch::getRandomFloatValue(1.f, 360.f),
			entitySeparationDistance, i, entityGenerationPoint);
		mainFlockingEntityList.back().setObstacleBehavioursInfo(FlockingObstacle(100.f, 100.f, mainFlockingEntityList.back().getPosition()));
		mainFlockingEntityList.back().setMagnetBehavioursInfo(FlockingMagnet(100.f, 30.f, mainFlockingEntityList.back().getPosition()));
	}

auto mainFlock = std::make_unique<Flock>(mainFlockingEntityList, entitiesSpeed, entitiesNeighborhoodZone, windowSize, timeToStartFlocking, FlockingAlgorithm::FlockingBehaviourParameters{});

Wiem że tego jest dużo, myślę że nawet nie ma sensu objaśniać co ja tu robię ( po prostu tworzę obiekt o nazwie mainFlock ).Tak naprawdę znaczenie ma tylko to wywołanie:

	mainFlockingEntityList.emplace_back(std::make_unique<ClassicFishShape>( ClassicFishShape(sf::Vector2f(20.f, 30.f), std::string("fish.png"), SMALL_FISH)), AdditionalMatch::getRandomFloatValue(1.f, 360.f), entitySeparationDistance, i, entityGenerationPoint);

Korzystam w tym momencie z kontenera std::list i wywołuje metodę emplace_back, tak wygląda konstruktor klasy dodawanego do listy obiektu:

Entity::Entity(std::unique_ptr<EntityShape> entityShape, float angle, float separationSquareRootZone, int ID, sf::Vector2f position)
		: m_SeparationCubedZone(std::pow(separationSquareRootZone, 2)), m_ID(ID), m_eventStaff(nullptr) {

		angle *= AdditionalMatch::DEGREES_TO_RADIANS;
		m_velocity = sf::Vector2f(std::cos(angle), std::sin(angle));
		m_entityShape = std::move(entityShape);
		m_entityShape->setPosition(position);
	}

konstruktor kopiujący jest tu usunięty:

Entity(const Entity& entity) = delete;

Myślę że ważna jest ta linijka:

m_entityShape = std::move(entityShape);

pamięć przydzielam w wywołaniu konstruktora a tu tylko przenoszę wskaźnik.

Wszystko tu działa bez zarzutów. Koszmar się zaczął kiedy zamieniłem wszędzie kontener std::list na std::vector. Pojawił się błąd:

Z tego "ciągu znaków" zrozumiałem tyle że brakuje mi konstruktora kopiującego, nie mam pojęcia czemu wywołanie emplace_back dla std::list go nie wymaga a dla std::vector już tak, ale mi zostało tylko się podporządkować do wymagań kontenerów STL... 

Więc dodałem konstruktor kopiujący:

Entity::Entity(Entity& entity)
		: m_SeparationCubedZone(entity.m_SeparationCubedZone), m_ID(entity.m_ID), m_eventStaff(nullptr){
		m_velocity = entity.m_velocity;
                m_entityShape = std::make_unique<???>(*entity.m_entityShape); 
              
	}

Pewnie pytacie się czemu w miejsce nawiasów ostrych dałem pytajniki, to jest właśnie główny mój problem. Nie wiem co mam tu dać.

Jak zerkniemy do zwykłego konstruktora to widać:

std::unique_ptr<EntityShape> entityShape

EntityShape to klasa bazowa, jak widać na początku, może ona wskazywać na dowolną klasę pochodną:

mainFlockingEntityList.emplace_back(std::make_unique<ClassicFishShape>(...),...); 

podczas wywołania konstruktora podaję jaki typ klasy pochodnej chcę stworzyć.

Wracając do tego momentu:

m_entityShape = std::make_unique<???>(*entity.m_entityShape); 

skąd ja mam wiedzieć na jaki typ klasy pochodnej wcześniej wskazywał entity.m_entityShape? W nawiasach muszę podać typ żeby dokonać kopii, a ja go nie znam ( wiem tylko tyle że sam wskaźnik jest typu klasy bazowej... ). Próbowałem jakoś to tak rozegrać:

m_entity = std::make_unique<decltype(entity.m_entity)>(*entity.m_entity);

Ale po pierwsze nie wydaje mi się to poprawnym rozwiązaniem, a po drugie powoduje to masę błędów. Nie mam zielonego pojęcia jak mam to zrobić :(

Z góry bardzo dziękuję, jeśli czegoś nie rozumiecie a chcecie pomóc to pytajcie ;)

Tu jest cały kod: https://github.com/Jakub1010/Flocking-Algorithm-Project

tyle że wcześniejszy, ten na listach co jeszcze działa poprawnie. Najważniejsze są tam pliki Flocking.h, Flocking.cpp i main.cpp.

 

komentarz zamknięcia: problem rozwiązany.
1
komentarz 31 marca 2019 przez mokrowski Mędrzec (155,460 p.)

BTW.

https://pl.wikipedia.org/wiki/Prawo_Demeter

np.

mainFlockingEntityList.back().setMagnetBehavioursInfo(FlockingMagnet(100.f, 30.f, mainFlockingEntityList.back().getPosition())

 

komentarz 1 kwietnia 2019 przez Jakub 0 Pasjonat (23,120 p.)
tzn? Mógłbyś rozszerzyć? Z góry dzięki.
1
komentarz 2 kwietnia 2019 przez mokrowski Mędrzec (155,460 p.)

Dość proste. Jeśli pytasz obiekt w funkcji o obiekt który zwraca a na nim wykonujesz operację która zwraca inny obiekt, który posiada metodę która zwraca ...  to masz takie "zapuszczenie korzeni" w aplikacji że będzie Ci to bardzo niewygodnie rozplątywać.

Nieco humorystycznie:

if(ciocia.zapytajWójka("jak załatwić pompkę").załatwZzamianąNa(staryRower).pompuj(kołoWózka).zmierzSiłę() < 20Kg) {
    //... 
}

Zaczynasz od Ciotki a kończysz na kilogramach posiadając zbędną wiedzę co się dzieje po drodze. Zbędną z punktu widzenia kodu w którym teraz jesteś.

Poza tym konieczność kopiowania std::unique_ptr świadczyć może o nieadekwatnym wyborze środków (tu wskaźnika) do zadania.

komentarz 3 kwietnia 2019 przez Jakub 0 Pasjonat (23,120 p.)

Dziękuje za objaśnienie :) teraz zamieniłem zapis:

mainFlockingEntityList.back().setMagnetBehavioursInfo(FlockingMagnet(100.f, 30.f, mainFlockingEntityList.back().getPosition())

na:
 

mainFlockingEntityList.back().setObstacleBehavioursInfo(100.f,100.f);
mainFlockingEntityList.back().setMagnetBehavioursInfo(100.f,30.f);

Teraz odpowiednia metoda sama bierze odpowiedzialność za ustawianie tego.

1 odpowiedź

0 głosów
odpowiedź 31 marca 2019 przez j23 Mędrzec (194,920 p.)
wybrane 31 marca 2019 przez Jakub 0
 
Najlepsza

Dodaj do EntityShape wirtualną metodę tworzącą kopie obiektu (zaimplementowaną oczywiście po stronie klas pochodnych).

komentarz 4 kwietnia 2019 przez Jakub 0 Pasjonat (23,120 p.)

Nie wiem, po co wywołujesz setPosition na obiekcie, który jest przenoszony.

Sam do końca nie wiem, bez tego pozycja sama się nie ustawi. Wydaje mi się że wynika to z tego że position jest składową klasy tego obiektu:

sf::RectangleShape m_fish;

Jest to już samo "dno abstrakcji" a więc klasa biblioteki SFML. Widocznie w konstruktorze kopiującym tej klasy nie zaimplementowano kopiowania pozycji obiektu. Innej opcji raczej nie ma...

Generalnie to uaktualniłem pytanie/komentarz bo już sam zdałem sobie sprawę z tego co zawaliłem. Jak byś mógł jeszcze raz zerknąć ;) Z góry dziękuje wink

komentarz 4 kwietnia 2019 przez j23 Mędrzec (194,920 p.)

Sam do końca nie wiem, bez tego pozycja sama się nie ustawi.

Jak nie ustawi, skoro przenosisz na własność wskaźnik na ten obiekt do innej klasy?

komentarz 4 kwietnia 2019 przez j23 Mędrzec (194,920 p.)
mainFlockingEntityList.push_back(Entity(....));

Użyj emplace_back.

Flock::Flock(std::vector<Entity>& entities, ...)
: ..., m_entities(std::move(entities)),

entities powinieneś zrobić r-referencją (teraz trochę to bałamutne).

 

komentarz 4 kwietnia 2019 przez Jakub 0 Pasjonat (23,120 p.)

W sumie to problem był w tym że kopiowania pozycji nie dodałem od konstruktora kopiującego klasy EntityShape:

ClassicFishShape(const ClassicFishShape& obj)
		: ClassicFishShape(obj.m_fish.getSize(), obj.m_textureLocation, obj.m_flockingObjectType) {
		m_fish.setPosition(obj.getPosition());
	}

Teraz już to załatwiłem w tamtym miejscu i w tych konstruktorach mogę to pominąć, co nie zmienia faktu że obiekt typu sf::RectangleShape sam tego za mnie nie zrobi.

Najgorsze jest to że kiedy jeden z konstruktorów ( tych trzech klasy Entity ) celowo zepsułem ( nie kopiowałem obiektu m_entityShape ) to było tylko o część obiektów ( tych ryb :) ) mniej. Tak jakby za każdym razem rzeczywiście był wykorzystywany losowo inny konstruktor...

komentarz 4 kwietnia 2019 przez Jakub 0 Pasjonat (23,120 p.)

@j23

Początkowo miałem emplace_back, widocznie zastąpiłem to push_back'iem poszukując błędu i zapomniałem zmienić z powrotem.

Tak dla informacji, teraz wywołuje mi się dla Entity tylko konstruktor zwykły i kopiujący ( bez przenoszącego ). W sumie to nwm do końca dlaczego.

Musiałem też zamienić dodatkowo:

auto mainFlock = std::make_unique<Flock>(mainFlockingEntityList, entitiesSpeed, entitiesNeighborhoodZone, displayAreaSize, timeToStartFlocking, FlockingAlgorithm::FlockingBehaviourParameters{});

na:

auto mainFlock = std::make_unique<Flock>(std::move(mainFlockingEntityList), entitiesSpeed, entitiesNeighborhoodZone, displayAreaSize, timeToStartFlocking, FlockingAlgorithm::FlockingBehaviourParameters{});

Ale to raczej oczywiste.

Podobne pytania

0 głosów
1 odpowiedź 728 wizyt
pytanie zadane 30 września 2017 w Grafika i multimedia przez DODO Bywalec (2,950 p.)
0 głosów
0 odpowiedzi 216 wizyt
0 głosów
1 odpowiedź 145 wizyt
pytanie zadane 27 maja 2016 w Sieci komputerowe, internet przez Wiiiciu Obywatel (1,090 p.)

92,551 zapytań

141,399 odpowiedzi

319,531 komentarzy

61,938 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...