Подтвердить что ты не робот

Может ли std:: map:: iterator возвращать копию значения или самого значения?

Я пытаюсь создать карту внутри карты:

typedef map<float,mytype> inner_map;
typedef map<float,inner_map> outer_map;

Смогу ли я поместить что-то внутри внутренней карты, или iterator:: second возвращает копию?

stl_pair.h предлагает последнее:

74: _T2 second;          ///< @c second is a copy of the second object

но моя тестовая программа отлично работает с таким кодом:

it = my_map.lower_bound(3.1415);
(*it).second.insert(inner_map::value_type(2.71828,"Hello world!");

Итак, где же правда? Это копия или нет?

4b9b3361

Ответ 1

Комментарий в stl_pair.h вводит в заблуждение в этом конкретном случае.

Не будет копии, так как map::iterator на самом деле ссылается на исходные данные внутри карты (value_type, которая сама является pair), а не копией. Таким образом, iterator::second также относится к исходным данным.

Ответ 2

Я хочу добавить ответ на этот вопрос для людей, использующих итераторы С++ 11...

Следующий код:

std::map<std::string, std::string> m({{"a","b"},{"c","d"}});
for (auto i : m)
{
    std::cout << i.first << ": " << i.second << std::endl;
}

копирует ключ и значение, так как "auto" является значением по умолчанию, а не ссылкой на const (по крайней мере, как он ведет себя clang 3.1).

Кроме того, код:

std::map<std::string, std::string> m({{"a","b"},{"c","d"}});
for (const std::pair<std::string,std:string>& i : m)
{
    std::cout << i.first << ": " << i.second << std::endl;
}

также копирует ключ и значение, так как правильный код должен быть:

std::map<std::string, std::string> m({{"a","b"},{"c","d"}});
for (const auto& i : m)
{
    std::cout << i.first << ": " << i.second << std::endl;
}

или

std::map<std::string, std::string> m({{"a","b"},{"c","d"}});
for (const std::pair<const std::string,std:string>& i : m)
{
    std::cout << i.first << ": " << i.second << std::endl;
}

Ответ 3

Карта value_type - это пара, и поэтому она имеет элементы первой и второй. Как и во всех итераторах, итератор карты является псевдо-указателем, то есть указывает на данные в коллекции, а не на копии этих данных.

Почти наверняка внутренне содержать указатели, а не ссылки, из-за того, что итераторы могут быть повторно назначены (для этого вы их используете), и вы не можете переназначить ссылки для ссылки на другие объекты.

Даже если у вас есть const_iterator, а тип под ним - POD, он должен иметь указатель на него, если кто-то это сделает:

map< int, int > m;
m.insert( make_pair( 1, 2 );
map<int,int>::const_iterator citer = m.begin();
map<int,int>::iterator iter = m.begin();
iter->second = 3;
std::cout << citer->second << '\n'; // should always print 3

Поведение должно быть определено и должно выводиться 3, что не произойдет, если const_iterator решил "оптимизировать" после него const и только int...