Как выполнить итерацию по карте STL, полной строк в C++
у меня есть следующая проблема, связанная с итерацией по ассоциативному массиву строк, определенных с помощью std::map.
-- snip --
class something
{
//...
private:
std::map<std::string, std::string> table;
//...
}
в конструкторе я заполняю таблицу парами строковых ключей, связанных со строковыми данными. Где-то еще у меня есть метод toString, который возвращает строковый объект, содержащий все ключи и связанные данные, содержащиеся в объекте таблицы(как ключ=формат данных).
std::string something::toString()
{
std::map<std::string, std::string>::iterator iter;
std::string* strToReturn = new std::string("");
for (iter = table.begin(); iter != table.end(); iter++) {
strToReturn->append(iter->first());
strToReturn->append('=');
strToRetunr->append(iter->second());
//....
}
//...
}
когда я пытаюсь скомпилировать я получаю следующее
ошибка: "ошибка: не подходит для вызова ‘(СТД::элементах, с std::распределитель >) ()’".
спасибо!
8 ответов:
ваша главная проблема заключается в том, что вы вызываете метод, называемый
first()
в итераторе. Что вы должны сделать, это использовать свойствоfirst
:...append(iter->first) rather than ...append(iter->first())
как вопрос стиля, вы не должны использовать
new
создать эту строку.std::string something::toString() { std::map<std::string, std::string>::iterator iter; std::string strToReturn; //This is no longer on the heap for (iter = table.begin(); iter != table.end(); ++iter) { strToReturn.append(iter->first); //Not a method call strToReturn.append("="); strToReturn.append(iter->second); //.... // Make sure you don't modify table here or the iterators will not work as you expect } //... return strToReturn; }
edit: facildelembrar указал (в комментариях), что в современном C++ теперь можно переписать цикл
for (auto& item: table) { ... }
не писать
toString()
метод. Это не Java. Реализуйте оператор потока для вашего класса.предпочитайте использовать стандартные алгоритмы над написанием собственного цикла. В этой ситуации
std::for_each()
обеспечивает хороший интерфейс для того, что вы хотите сделать.если вы должны использовать цикл, но не намерены менять данных, предпочитают
const_iterator
overiterator
. Таким образом, если вы случайно попытаетесь изменить значения, компилятор предупредит вас.затем:
std::ostream& operator<<(std::ostream& str,something const& data) { data.print(str) return str; } void something::print(std::ostream& str) const { std::for_each(table.begin(),table.end(),PrintData(str)); }
затем, когда вы хотите распечатать его, просто поток объекта:
int main() { something bob; std::cout << bob; }
Если вам действительно нужно строковое представление объекта, вы можете использовать
lexical_cast
.int main() { something bob; std::string rope = boost::lexical_cast<std::string>(bob); }
детали, которые должны быть заполнены.
class somthing { typedef std::map<std::string,std::string> DataMap; struct PrintData { PrintData(std::ostream& str): m_str(str) {} void operator()(DataMap::value_type const& data) const { m_str << value.first << "=" << value.second << "\n"; } private: std::ostream& m_str; }; DataMap table; public: void something::print(std::ostream& str); };
измените свои вызовы append, чтобы сказать
...append(iter->first)
и
... append(iter->second)
дополнительно строку
std::string* strToReturn = new std::string("");
выделяет строку в куче. Если вы намереваетесь фактически вернуть указатель на эту динамически выделенную строку, возврат должен быть изменен на std::string*.
кроме того, если вы не хотите беспокоиться об управлении этим объектом в куче, измените локальное объявление на
std::string strToReturn("");
и изменить, "добавить" звонки для использования ссылочного синтаксиса...
strToReturn.append(...)
вместо
strToReturn->append(...)
имейте в виду, что это будет построить строку в стеке, то скопировать это в возвращаемую переменную. Это имеет последствия для производительности.
обратите внимание, что результатом разыменования std::map:: iterator является std:: pair. Значения
first
иsecond
это не функции, это переменные.изменения:
iter->first()
до
iter->first
то же самое с
iter->second
.
использование:
std::map<std::string, std::string>::const_iterator
вместо:
std::map<std::string, std::string>::iterator
в c++11 вы можете использовать
for ( auto iter : table ) { key=iter->first(); value=iter->second(); }
еще одна достойная оптимизация -c_str () член STL string classes, который возвращает неизменяемую строку с нулевым завершением, которая может быть передана как LPCTSTR, например, к пользовательской функции, которая ожидает LPCTSTR. Хотя я не проследил через деструктор, чтобы подтвердить это, я подозреваю, что класс string заботится о памяти, в которой он создает копию.