Функция возвращающая ассоциативный массив!?
Подскажите могу я такое сделать:
хидер:
{
char Name[256];
char Rest[256];
char Price[256];
} MyStruct;
typedef map<double, MyStruct> MyMap;
MyMap* __fastcall TForm1::FileParcer();
модуль:
{
//
}
в модуле ругается:
[C++ Error] Unit1.cpp(69): E2141 Declaration syntax error
В принципе функция может возвращать контейнер или нет? Если да, то что я делаю не так?
Добрый день!
Подскажите могу я такое сделать:
хидер:
{
char Name[256];
char Rest[256];
char Price[256];
} MyStruct;
typedef map<double, MyStruct> MyMap;
MyMap* __fastcall TForm1::FileParcer();
модуль:
{
//
}
в модуле ругается:
В принципе функция может возвращать контейнер или нет? Если да, то что я делаю не так?
В принципе ничто не мешает возвращать контейнер - это такой же тип данных как и все остальные.
Но обычно возращают итератор. :)
Ошибка вероятно не связана с тем что возвращает функция - скорее всего ты не учел область видимости объявления.
Ошибка вероятно не связана с тем что возвращает функция - скорее всего ты не учел область видимости объявления.
Ты был прав, с областью видимости намудрил. :)
Я с STL вот только начал знакомиться, поэтому не очень еще понимаю.
Как я понял итератор это тот же указатель, но тогда какой смысл возвращать итератор на контейнер, если можно вернуть сам контейнер или я что-то не так понял?
вот так правильно делать?:
MyMap Map1;
void function1()
{
MyMap::iterator pos;
pos = function2();
// Производим операции с контейнером
}
MyMap::iterator function2()
{
MyMap::iterator pos;
// Производим операции с контейнером
return pos;
}
Я с STL вот только начал знакомиться, поэтому не очень еще понимаю.
Как я понял итератор это тот же указатель, но тогда какой смысл возвращать итератор на контейнер, если можно вернуть сам контейнер или я что-то не так понял?
Работа с контейнерами достаточно прожорлива по памяти. Поэтому возвращая контейнер(или указатель на него) ты можешь получить немаленькие утечки (и если бы только утечки :) ) за счет создания темп-объектов.
вот так правильно делать?:
MyMap Map1;
void function1()
{
MyMap::iterator pos;
pos = function2();
// Производим операции с контейнером
}
MyMap::iterator function2()
{
MyMap::iterator pos;
// Производим операции с контейнером
return pos;
}
Хм. Я бы предпочел так:
{
// Производим операции с контейнером
}
//Или
void function1(MyMap::iterator pos)
{
// Производим операции с элементом
}
тогда функцию используешь так:
...
//Заполнили, инициализировали
//Здесь обрабатываем
function1(List.begin,List.end,1);
//или
...
Это не значит, что мое решение более "правильное" чем твое - все зависит от того что ты хочешь получить на выходе. Кроме того, используя контейнеры, я бы рекомендовал тебе использовать алгоритмы и шаблоны функций из STL в первую очередь. Большинство задач, таких как поиск, сортировки, максимумы, минимумы, в общей сложности ок 70 алгоритмов там решены - потрать некоторое время на ознакомление и возможно ты не создаш себе кучу проблем. :)
есть файлик довольно таки большой 50000 строк (постоянно растет), его необходимо отпарсить и запихать в структуру, причем у каждой строчки есть свои идентификатор т.е. ключ, потом по этому ключу необходимо будет выполнять поиск значений.
Вот что я решил сделать:
1. Создаю структуру вида:
{
char Name[256];
char Price[256]; // Именно char
char Rest[256]; // нужен
} MyStruct;
2. Создаю контейнер map<string, MyStruct> (т.к. поиск по ключу самый быстрый, дубликатов нет)
3. Парсю файлик и заполняю контейнер (вот это необходимо оформить в виде функции, т.к. будет многократный вызов)
Так если сделать, чтобы функция возвращала итератор, то контейнер необходимо объявлять на уровне модуля, а не на уровне функции!
Может подскажешь как можно это лучше реализовать?
Задача у меня следующая:
есть файлик довольно таки большой 50000 строк (постоянно растет), его необходимо отпарсить и запихать в структуру, причем у каждой строчки есть свои идентификатор т.е. ключ, потом по этому ключу необходимо будет выполнять поиск значений.
Вот что я решил сделать:
1. Создаю структуру вида:
{
char Name[256];
char Price[256]; // Именно char
char Rest[256]; // нужен
} MyStruct;
2. Создаю контейнер map<string, MyStruct> (т.к. поиск по ключу самый быстрый, дубликатов нет)
3. Парсю файлик и заполняю контейнер (вот это необходимо оформить в виде функции, т.к. будет многократный вызов)
Так если сделать, чтобы функция возвращала итератор, то контейнер необходимо объявлять на уровне модуля, а не на уровне функции!
Может подскажешь как можно это лучше реализовать?
Я честно говоря не вижу особой выгоды в использовании т.н. "локального" контейнера, накладные расходы возможно будут гораздо выше - это раз.
Второе - я создал бы отдельно сингл-класс массива строк и в нем в качестве поля контейнер. Здесь бы реализовал все операции для работы со строками и функцию загрузки данных.
И отдельный класс для чтения данных, объект которого создавался бы в этой функции. Примерно вот так:
TLoadDocument loaddoc;//Класс для загрузки
TInvoiceIn document;//Класс документа
clearAll(); //Чистим контейнер
loaddoc.Open(f,ios::in|ios::binary);
while(loaddoc.size){
//Вызывается перегруженный оператор чтения из потока
loaddoc >> document;
//Функция заполнения контейнера.
insertDocument(document,document.GetCode());
}
loaddoc.close();
}
int __fastcall TListDocument::insertDocument(const TInvoiceIn& doc,int recordId)throw(DuplicateId){
if(recordId ==0)recordId = nextId++;
else if(recordId >= nextId)nextId = recordId +1;
else if (documentcode.count(recordId))throw DuplicateId();
TInvoiceIn *docum = new TInvoiceIn(doc);
docum->SetCode(recordId);
//documentcode и documentname - два контейнера которые заполняются
// один типа multiset - в него вставляется собственно объект
//второй map - содержит идентификатор и итератор на multiset
DocumentName::iterator i=documentname.insert(*docum);
documentcode[recordId] =i;
return recordId;
}
Идея с двумя контейнерами позаимствована из "STL на примерах".
Я честно говоря не вижу особой выгоды в использовании т.н. "локального" контейнера, накладные расходы возможно будут гораздо выше - это раз.
Второе - я создал бы отдельно сингл-класс массива строк и в нем в качестве поля контейнер. Здесь бы реализовал все операции для работы со строками и функцию загрузки данных.
И отдельный класс для чтения данных, объект которого создавался бы в этой функции.
идея понятна.
Примерно вот так:
TLoadDocument loaddoc;//Класс для загрузки
TInvoiceIn document;//Класс документа
clearAll(); //Чистим контейнер
loaddoc.Open(f,ios::in|ios::binary);
while(loaddoc.size){
//Вызывается перегруженный оператор чтения из потока
loaddoc >> document;
//Функция заполнения контейнера.
insertDocument(document,document.GetCode());
}
loaddoc.close();
}
int __fastcall TListDocument::insertDocument(const TInvoiceIn& doc,int recordId)throw(DuplicateId){
if(recordId ==0)recordId = nextId++;
else if(recordId >= nextId)nextId = recordId +1;
else if (documentcode.count(recordId))throw DuplicateId();
TInvoiceIn *docum = new TInvoiceIn(doc);
docum->SetCode(recordId);
//documentcode и documentname - два контейнера которые заполняются
// один типа multiset - в него вставляется собственно объект
//второй map - содержит идентификатор и итератор на multiset
DocumentName::iterator i=documentname.insert(*docum);
documentcode[recordId] =i;
return recordId;
}
Идея с двумя контейнерами позаимствована из "STL на примерах".
но вот реализация :(
придется похоже копаться в STL и делать по-своему.
спасибо.
возвращать итератор имхо не есть гут, ибо не дай боже содержимое контейнера изменится - получишь невалидный итератор, что чревато последствиями
Дабы избежать накладных расходов на копирование при передаче по значению, я бы предложил передавать контейнер по ссылке, что то вроде этого:
возвращать итератор имхо не есть гут, ибо не дай боже содержимое контейнера изменится - получишь невалидный итератор, что чревато последствиями
Мне нужно контейнер не передавать в функцию, а возвращать из функции. :)
Мне нужно контейнер не передавать в функцию, а возвращать из функции. :)
1) А что мешает объявить контейнер вне функции, передать по ссылке и работать дальше.
2) Можно сделать так например:
{
static MyMap m_filestorage;
...
// тута делаешь работу
...
return m_filestorage;
}
хотя по моему вариант 1 - предпочтительней
1) А что мешает объявить контейнер вне функции, передать по ссылке и работать дальше.
2) Можно сделать так например:
{
static MyMap m_filestorage;
...
// тута делаешь работу
...
return m_filestorage;
}
хотя по моему вариант 1 - предпочтительней
по-первому варианту сделал, все работает, спасибо!