Jak poprawnie zainicjalizować mapę używając funkcji stl

0

Hej, mam takie pytanie, w mapach jestem zielony, wiem mniej więcej o co w nich chodzi, że to kontener asocjacyjny, szukamy po kluczu itd.
Nie mam doświadczenia w stosowaniu ich.

Mam takie pytanie, czy taka składanka ma sens i co tam robi make pair.

myMap.push_back(std::move(std::make_pair(key, value)));

czy to jest jest to samo ?

myMap.emplace(key, value);

Załóżmy, że value to obiekt albo nawet wskaźnik na obiekt.

i dlaczego tutaj to nie działa.

myMap.insert(std::make_pair(key, std::move(value)));```
0

czy taka składanka ma sens

Nie, std::map nie ma metody push_back. Zajrzyj tu -> link

co tam robi make pair.

Robi parę (jak sama nazwa wskazuje) :)

i dlaczego tutaj to nie działa.

Nie działa, czyli co? Nie kompiluje się?

1

Za dużo kombinujesz.

myMap[key] = value;
0

Mam zrobione coś takiego

std::unique_ptr<myClass> ptr(new myClass());

I chce to dodać do mojej mapy której definicja wyglada tak:

std::map<idEnumClass, std::unique_ptr<myClass>> myMap;

I wywala mi blad przy tym:

myMap.insert(std::make_pair(idEnumClass, std::move(ptr)));
0

W pierwszym parametrze std::make_pair powinieneś dać wartość typu idEnumClass, a nie typ.

Jestem pewny, że w logu kompilacji masz jasno napisane, w czym jest problem.

0
kameleo327 napisał(a):
myMap.push_back(std::move(std::make_pair(key, value)));

czy to jest jest to samo ?

myMap.emplace(key, value);

Zakładając, że chodziło Ci o insert zamiast push_back (nieistniejącego dla mapy, jak już ktoś wcześniej wspominał) to nie.
Te dwa zapisy robią prawie to samo i zwracają też prawie to samo, chociaż jeśli nie ma takiego elementu w mapie i nowy element jest tam umieszczony, to efekt finalny jest dla obu konstrukcji taki sam.
Fajnie opisane jest to na SO.

0
void cResourceManager::load(const std::string& filePath, cResourceManager::identifier id)
{
	std::unique_ptr<sf::Texture> resource(new sf::Texture);
	if (resource->loadFromFile(filePath))
		resourceMap.insert(std::pair<identifier, std::unique_ptr<sf::Texture>>(id, std::move(resource)));
}

Tak wygląda funkcja. Kompiluje się ale w debugerze przy wykonywaniu polecenia insert otwiera plik xmemory0 i wyświetla :> Zgłoszono wyjątek: naruszenie dostępu do odczytu.

std::forward<std::_Tree_node<std::pair<enum cResourceManager::identifier const std::unique_ptr<sf::Texture,std::default_delete<sf::Texture> > >,void *> * &>(...) zwrócił 0x4.
0

Przekombinowałeś. Spróbuj na przykład wykorzystać std::shared_ptr
I korzystaj z std::make_shared i std::make_unique wtedy będzie Ci łatwiej to ogarnąć.

edit: Czym to kompilujesz? Gdy u siebie wykonuję Twój kod zastępując cResourceManager::identifier zwykłym int'em nie mam żadnego problemu i insert wykonuje się poprawnie.
Może problem leży w przekazywaniu parametru id?

0

W kodzie nie widzę błędu. Pokaż jak wywołujesz cResourceManager::load.

0
kameleo327 napisał(a):
void cResourceManager::load(const std::string& filePath, cResourceManager::identifier id)
{
	std::unique_ptr<sf::Texture> resource(new sf::Texture);
	if (resource->loadFromFile(filePath))
		resourceMap.insert(std::pair<identifier, std::unique_ptr<sf::Texture>>(id, std::move(resource)));
}

Tak wygląda funkcja. Kompiluje się ale w debugerze przy wykonywaniu polecenia insert otwiera plik xmemory0 i wyświetla :> Zgłoszono wyjątek: naruszenie dostępu do odczytu.

std::forward<std::_Tree_node<std::pair<enum cResourceManager::identifier const std::unique_ptr<sf::Texture,std::default_delete<sf::Texture> > >,void *> * &>(...) zwrócił 0x4.

Jaki jest sens wykonywania std::move na obiekcie typu unique_ptr? Przecież już samo użycie smart pointera daje Ci to, że nie przenosisz całego obiektu sf::Texture tylko ten pointer, więc spokojnie możesz to zrobić przez wartość.

Użycie std::move nic nie przenosi, tylko robi casta do std::unique_ptr<sf::Texture>&& czyli do r-value reference na ten unique_ptr. Podejrzewam, że to powoduje wywołanie się konstruktora std::pair przyjmującego &&, a to oznacza, że będzie on chciał gdzie wpisać NULLa.

Pozbądź się std::move i powinno być dobrze.

2

Move jest niezbędne, inaczej wybrany zostanie konstruktor kopiujący, a unique ptr nie może być kopiowany.

0

tak wygląda wywołanie

resourceManager->load("textures/texture.png", cResourceManager::identifier::basicCharacterTexture)

a identifier jest tutaj

class cResourceManager
{
public:
	enum class identifier
	{
		basicCharacterTexture
	};
// ...
};

bazowałem na tym https://github.com/SFML/SFML-Game-Development-Book/blob/master/02_Resources/Include/Book/ResourceHolder.inl

0
kq napisał(a):

Move jest niezbędne, inaczej wybrany zostanie konstruktor kopiujący, a unique ptr nie może być kopiowany.

Ok, przeoczyłem to. A czy nie można w takim razie użyć po prostu shared_ptr, którego spokojnie można kopiować, bez żadnego std::move?

0

Można, tylko to pomysł kompletnie bez sensu. Nie używa się shared_ptr tylko dlatego, że nie chce ci się dopisać kilku znaków gdy przenosisz zasób.

0
kq napisał(a):

Można, tylko to pomysł kompletnie bez sensu. Nie używa się shared_ptr tylko dlatego, że nie chce ci się dopisać kilku znaków gdy przenosisz zasób.

Zależy od punktu widzenia. Dla mnie bez sensu jest przenoszenie zasobu, który można skopiować.

0

@kameleo327: trochę mało tego kodu. Sprawdź, czy resourceManager w chwili wywołania jest wciąż istniejącym obiektem lub czy nie został w jakiś sposób uszkodzony.

0

Boże....
Tak wyglądał konstruktor gdzie tworzony jest manager i dodawane są do niego tekstury

cGame::cGame()
{
// ...
resourceManager->load("textures/texture.png", cResourceManager::identifier::basicCharacterTexture);
//...
auto resourceManager = std::make_unique<cResourceManager>();
//...
}

Przepraszam za to. Jednak to prawda, że najciemniej pod latarnią... . Ale przynajmniej temat zyskał charakter mocno dydaktyczny :D

1 użytkowników online, w tym zalogowanych: 0, gości: 1