Получение объекта из множества

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Titarenko_Vlad
Сообщения: 20
Зарегистрирован: 12 ноя 2013, 21:50

Здравствуйте!
У меня есть класс с множеством

Код: Выделить всё

class AutoShop
{
	string name;
	string address;
	int amountCarsSold;
	double gainsMoney;
	set<Manager> managerSet;
	set<Client> clientSet;
	set<AutoConfiguration> autoConfigurationSet;
...
}
в AutoConfiguration есть поле id

Код: Выделить всё

class AutoConfiguration
{
	int id;
...
}
Мне нужно получить объект множества по определенному id. Вот что я делал:

Код: Выделить всё

template<class T> T& getObj(int _id)
	{
		set<T>::iterator iter;
		iter=getSet<T>().begin();
		while(iter!=getSet<T>().end())
		{
			if((*iter).getId()==_id)
				return *iter;
			iter++;
		}
	}
Так я ее вызывал:

Код: Выделить всё

getObj<AutoConfiguration>(id);
Получал такую ошибку: error C2440: 'return' : cannot convert from 'const AutoConfiguration' to 'AutoConfiguration &'
Попытался вернуть итератор на объект, как в алгоритме find():

Код: Выделить всё

template<class inpIter, class T> inpIter getObj(const int _id)
	{
		set<T>::iterator iter;
		iter=getSet<T>().begin();
		while(iter!=getSet<T>().end())
		{
			if((*iter++).getId()==_id)
				return iter;
		}
	}
Вызывал так:

Код: Выделить всё

set<AutoConfiguration>::iterator iter;
		iter=getObj<set<AutoConfiguration>::iterator, AutoConfiguration>(id)
все скомпилилось, но когда начал работать с объектом

Код: Выделить всё

(*iter).addModification();
выдало такую ошибку: error C2662: 'AutoConfiguration::addModification' : cannot convert 'this' pointer from 'const AutoConfiguration' to 'AutoConfiguration &'
Можете объяснить почему this константный и как это исправить что бы я мог работать с объектом?
Titarenko_Vlad
Сообщения: 20
Зарегистрирован: 12 ноя 2013, 21:50

я узнал что все объекты в множестве хранятся как конст...
то есть если у меня есть множество с объектами типа AutoConfiguration
set<AutoConfiguration> autoConfigurationSet;
то я не могу в этих объектах ничего изменить или добавить?
Как быть? что делают в таких ситуациях, если мне нужно потом работать с данными хранящимися в AutoConfiguration?
Titarenko_Vlad
Сообщения: 20
Зарегистрирован: 12 ноя 2013, 21:50

решил все при помощи const_cast
привожу пример:

Код: Выделить всё

template<class T> T* getObj(int _id)
	{
		set<T>::iterator iter;
		iter=getSet<T>().begin();
		while(iter!=getSet<T>().end())
		{
			if((*iter).getId()==_id)
				return const_cast<AutoConfiguration*>(&(*iter));
			iter++;
		}
	}
Вызов:

Код: Выделить всё

getObj<AutoConfiguration>(id)->addModification();
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Дело в том, что set внутри себя хранит данные в специальном дереве. Это сделано для того, чтобы обеспечивать быстрый поиск элементов set'а. Причём расположение объекта в конкретном месте дерева зависит от сожержимого объекта, точнее от того, что возвращает оператор < для этого объекта. Мы не имеем право разрешать менять объект внутри сэта, так как пользователь может поменять данные, влияющие на то, что вернёт оператор < (а это, в свою очередь, повлияет на распложение объекта в дереве, что мы не можем отследить, возвратив неконстантную ссылку). Исходя из всего этого, мы имеем константный доступ ко всем объектам внутри сэта. Мы можем добавить объект, удалить объект (тогда дерево перестроится), но пока объект внутри сета, менять мы его не можем.

Я клоню к тому, что если ты хочешь менять содержимое контейнера, то set тебе не подходит. Обычно set используют для того, чтобы добиться уникальности и сортировки данных. Ни одно, ни другое тебе не нужно. Но тебе нужно их менять, что в случае сета сделать не получится.

Вывод можно сделать один. Я ненавязчиво предлагаю переход на тот самый vector, который фигурировал в моём тестовом примере в твоей предыдущей теме. Вектор не хранит данные в хитром формате, поэтому позволяет их редактирование. Он, собственно, является прямым аналогом обычного С массива, только с возможностью динамического изменения размера. В каком порядке добавляем в вектор, в таком порядке элементы там и будут жить. Никаких автоматических сортировок (которые нам и не нужны, кстати). А если нужна проверка уникальности (чтобы два обекта с одинаковым id нельзя было добавить), то перед добавением просто пробегаем вектор и проверяем, что там таких объектов нет.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Titarenko_Vlad
Сообщения: 20
Зарегистрирован: 12 ноя 2013, 21:50

спасибо.
я выбрал сэт потому что мне нужно делать много запросов поиска(именно этим я руководствовался), про константность данных там совсем не было ничего сказано.
Скажите, а у map поиск реализован эффективнее? может лучше заменить сэты на map?
там где нет поиска у меня и так будет вектор, а хотелось бы задействовать побольше возможностей языка.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Можно использовать map, если не подразумевается замена id. В map ведь у нас есть разделение на ключ и значение. Ключ нельзя менять (как и в set весь объект нельзя менять, так как set -это упрощение map, в которой в качестве ключа выступает весь объект).

По поводу быстродействия - для всех вариантов vector будет работать быстрее, гарантрирую. Контейнеры map и set начинают давать прирост в быстродействии только на больших количествах данных (ну, скажем, более нескольких десятков).
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Titarenko_Vlad
Сообщения: 20
Зарегистрирован: 12 ноя 2013, 21:50

решил использовать map, но у меня какая-то мистика)
Геттеры создают новые объекты! Каждый раз при вызове геттера создается объект соответствующий параметру геттера

Код: Выделить всё

template <class T> map<int, T>& getMap();
template<> map<int, Manager>& getMap<Manager>();
template<> map<int, Client>& getMap<Client>();
template<> map<int, AutoConfiguration>& getMap<AutoConfiguration>();

template<> map<int, Manager>& AutoShop::getMap<Manager>()
{
	return mapManagers;
}
template<> map<int, Client>& AutoShop::getMap<Client>()
{
	return mapClients;
}
template<> map<int, AutoConfiguration>& AutoShop::getMap<AutoConfiguration>()
{
	return mapAutoConfigurations;
}
и я не могу понять где...
Titarenko_Vlad
Сообщения: 20
Зарегистрирован: 12 ноя 2013, 21:50

Изивине, обманул, проект не ребилднулся и выдал не тот результат
Дополнительный объект создается тут в строке присвоения объекта

Код: Выделить всё

template <class T> void add()
	{
		T obj;
		map<int, T>& mapSome=getMap<T>();
		mapSome[obj.getId()]=obj;
	}
Строка 5...
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

То есть пока работает всё, как хотелось?
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Titarenko_Vlad
Сообщения: 20
Зарегистрирован: 12 ноя 2013, 21:50

Вот теперь работает! вот 2 рабочих варианта

Код: Выделить всё

template <class T> void add()
	{
		/*T obj;
		getMap<T>().insert(pair<int,T>(obj.getId(), obj));*/
		getMap<T>()[(getMap<T>().size())+1];
	}
причина создания нового объекта была из-за того, что в это строке
mapSome[obj.getId()]=obj;
при вхождении в operator[] с параметром которого еще нет в map он автоматически создает объект. Там был как раз тот случай, я создал объект и по его id(которого еще нет в map) пытался что-то записать.
Ответить