Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Константны ли ключи в std::set ? учебник говорит - Да, жизнь - Нет 
V
    Опции темы
zim22
Дата 2.3.2009, 18:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 29
Всего: 69



Код, указанный ниже, отлично работает и меняет по итератору значение ключа в set. 
Но в книжке (Язык программирования С++. Вводный курс / С++ Primer, Fourth Edition) написано, что ключи в set константны и соответственно не поддаются изменению.
Может у меня компилятор свихнулся? smile

Цитата из книжки:
"Подобно тому, как в элементе карты нельзя изменить ключ, ключи набора (set) также константны. Если существует итератор на элемент набора, то все, что с ним можно сделать, - это прочитать ключ, а запись при помощи итератора невозможна.

То же самое в англ.версии книжки:
"Just as we cannot change the key part of a map element, the keys in a set are also const. 
If we have an iterator to an element of the set, all we can do is read it; we cannot write through it"

Код
#include <set>
#include <string>
#include <vector>
#include <iostream>
#include <map>

using namespace std;

int main(int argc, char *argv[])
{
    set<string> set1;
    set1.insert("the");
    set1.insert("and");
    
    set<string>::iterator it = set1.find("and");
    if (it != set1.end())
    {
        cout << *it << endl;
        *it = "life";
        cout << *it << endl;
    }    
    return 0;
}



--------------------
PM MAIL   Вверх
pan2004
Дата 2.3.2009, 19:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 357
Регистрация: 28.7.2007

Репутация: 2
Всего: 9



zim22, ну я как-то не вижу в приведенном тобой примере, чтобы ты ключи менял.
Судя по всему, ты спутал понятия ключ-значение(значение неконстантным итератором изменить естественно можно, на то он и неконстантный)


--------------------
Qt4/C++ fan
WinXP SP3: MSVC++2005 Qt4.5.1 Boost1.39
сыграем в дурака?
PM MAIL   Вверх
zim22
Дата 2.3.2009, 19:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 29
Всего: 69



pan2004, в моём коде были ещё комментарии, но я их удалил, в них указано, что мы оперируем именно ключами, а не значениями:
Код
  *it = "life"; // ошибка: ключи в наборе только для чтения
cout << *it << endl; // ok: читать ключи можно


Т.е. мы всё-таки оперирум с ключами, а не со значениями. Т.к. контейнер set в MSDN описывается как содержащий только ключи, а не значения:

"An STL set is: 
An associative container, which a variable size container that supports the efficient retrieval of element values based on an associated key value. Further, it is a simple associative container because its element values are its key values."


--------------------
PM MAIL   Вверх
bsa
Дата 3.3.2009, 01:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Цитата(C++ Standard 2003 Draft @  page 596)
iterator of an associative container is of the bidirectional iterator category. For associative containers where the value
type is the same as the key type, both iterator and const_iterator are constant iterators
. It is unspecified whether
or not iterator and const_iterator are the same type.
т.е. в стандарте написано, что std::set::iterator ведет себя так же, как std::set::const_iterator, но не определено, должен ли первый являться вторым или нет. Более того, думаю, что не должен, так как константный итератор нельзя использоваться в std::set::erase, в то время как обычный можно.
PM   Вверх
azesmcar
Дата 3.3.2009, 07:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Цитата

учебник говорит - Да, жизнь - Нет


Жизнь такого не говорит!!! Это Visual Studio упорно так твердит потому что по инерции продолжает не соответствовать стандарту. На GCC попробуй, результат совершенно другой.

bsa

Да, вести себя они должны одинаково, но если для map или set изменить ключ он должен перестроить все дерево (я честно не пробовал, но сомневаюсь что студио это делает). Я сталкивался с тем же самым..сам был удивлен, как такое возможно, почитал стандарт, попробовал на GCC - все встало на свои места smile

Код

#include <iostream>
#include <map>

int main()
{
    typedef std::map<int, std::string> mmap;
    mmap m;
    m.insert(mmap::value_type(1, "string1"));
    m.insert(mmap::value_type(2, "string2"));
    m.insert(mmap::value_type(3, "string3"));
    m.insert(mmap::value_type(4, "string4"));

    mmap::iterator it = m.find(2);
    it->first = 1; //error C3892: 'it' : you cannot assign to a variable that is const
};


В 2008 студии уже исправили


Это сообщение отредактировал(а) azesmcar - 3.3.2009, 07:54
PM   Вверх
vinter
Дата 3.3.2009, 07:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 8
Всего: 56



Цитата(zim22 @  2.3.2009,  19:32 Найти цитируемый пост)
Цитата из книжки:"Подобно тому, как в элементе карты нельзя изменить ключ, ключи набора (set) также константны. Если существует итератор на элемент набора, то все, что с ним можно сделать, - это прочитать ключ, а запись при помощи итератора невозможна.



Цитата(azesmcar @  3.3.2009,  08:45 Найти цитируемый пост)
Это Visual Studio упорно так твердит потому что по инерции продолжает не соответствовать стандарту.

а ты стандарт открыл, прежде чем сказать ерунду?
обьявления из стандарта.
Код

// set operations:
iterator find(const key_type& x);
const_iterator find(const key_type& x) const;

Цитата(standard)

 It is unspecified whether
or not iterator and const_iterator are the same type

т.е в стандарте по этому поводу ничего ясного нет. Студия поступает вполне корректно.

Добавлено через 2 минуты и 34 секунды
zim22, посмотри книгу Саттера, "Решение сложны задач на С++". Задача 1.15


--------------------
Мой блог
PM MAIL WWW   Вверх
azesmcar
Дата 3.3.2009, 08:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



vinter, красивая функция, но какое отношение имеет твоя функция find к тому что я написал?

Цитата

C++ Report, 11(9), October 1999.
An essential requirement, without which associative containers could not work reliably at all, is this: Once a key has been inserted into the container, that key had better not be changed in any way that would change its relative position in the container. If that ever did happen, the container wouldn't know about it and its assumptions about the ordering of its entries would be violated, searches for valid entries could fail, iterators would no longer be guaranteed to traverse the contents in key order, and in general Bad Things would happen.


Стандарт неохота открывать, да и не нужно читать стандарт чтобы узнать что менять ключь сета нельзя. А то что студия не соответствует стандарту давно известный факт, насчет 2008 не ручаюсь, но ранние версии точно. Полно проблем с шаблонами и STL.
PM   Вверх
azesmcar
Дата 3.3.2009, 08:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Вот вам и стандарт, открыл все таки, и вам бы не помешало перед тем как написанное другими ерундой называть.

Код

...
typedef pair<const Key, T> value_type;
...


PM   Вверх
vinter
Дата 3.3.2009, 08:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 8
Всего: 56



Цитата(azesmcar @  3.3.2009,  09:05 Найти цитируемый пост)
 но какое отношение имеет твоя функция find к тому что я написал?

ты отвечал на вопрос zim22, у которого в коде используется set и find.

Цитата(azesmcar @  3.3.2009,  09:05 Найти цитируемый пост)
Стандарт неохота открывать, да и не нужно читать стандарт чтобы узнать что менять ключь сета нельзя

можно его менять. Читай стандарт, это не запрещается. А что не запрещено, то разрешено.

Цитата(azesmcar @  3.3.2009,  09:05 Найти цитируемый пост)
Полно проблем с шаблонами и STL.

обычно в таких случаях приводят аргументы, иначе твои слова остаются пустословием.

Цитата(azesmcar @  3.3.2009,  09:24 Найти цитируемый пост)
typedef pair<const Key, T> value_type;

отлично, а map nne причем? Еще раз название темы перечитай.


--------------------
Мой блог
PM MAIL WWW   Вверх
azesmcar
Дата 3.3.2009, 09:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Цитата

ты отвечал на вопрос zim22, у которого в коде используется set и find.


но вопрос был не про find а про изменение ключа. Он и std::string использовал в своем примере, что нам теперь про std::string разговаривать?

Цитата

можно его менять. Читай стандарт, это не запрещается. А что не запрещено, то разрешено.


я уже привел цитату из стандарта и из журнала C++ Report. Этого мало?

Цитата

обычно в таких случаях приводят аргументы, иначе твои слова остаются пустословием.


Если тебе нужны аргументы - это отдельная тема которая не подлежит обсуждению в этом топике, скажу только что в шестой студии не работала частичная специализация а конструктор std::exception у них до сих пор принимает параметр std::string, хотя в стандарте описан иной интерфейс класса std::exception - в результате до фига непереносимого кода, потому что люди пишут throw std::exception("error").
В приоритетах выборки первичного шаблона были некоторые проблемы и (уже не помню) какой студии.
Если хочешь открой отдельную тему пообсуждаем.

Цитата

отлично, а map nne причем? Еще раз название темы перечитай. 


а map притом что без разницы. Просто для удобства привел пример на map, чтобы показать что ключь нельзя менять а значение можно.

Добавлено через 2 минуты и 25 секунд
ассоциативные контейнеры работают по одному принципу - построение дерева, если изменить значение - дерево станет недееспособным, потому без разницы.
PM   Вверх
zim22
Дата 3.3.2009, 09:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 29
Всего: 69



Цитата(vinter @  3.3.2009,  07:58 Найти цитируемый пост)
посмотри книгу Саттера, "Решение сложны задач на С++". Задача 1.15

понял, что ключи мне пока лучше не изменять, а удалять и создавать заново, чтобы не нарушилась внутренняя структура set.


--------------------
PM MAIL   Вверх
azesmcar
Дата 3.3.2009, 09:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Так...нашел.
Значит я правильно помнил, в 2008 тоже работало..

Код

    std::set<int> t;
    
    t.insert(1);
    t.insert(2);
    t.insert(3);
    t.insert(4);
    
    std::set<int>::iterator it = t.find(3);
    
    *it = 1;

    std::copy(t.begin(), t.end(), std::ostream_iterator<int>(std::cout, " "));


получаем в результате

1 2 1 4

насколько соответствует СТАНДАРТУ то что в ассоциативном контейнере set может быть два одинаковых ключа - думайте сами. Или мне привезти цитату из стандарта что set долже иметь уникальные ключи?

PM   Вверх
zim22
Дата 3.3.2009, 09:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 29
Всего: 69



Цитата(azesmcar @  3.3.2009,  09:05 Найти цитируемый пост)
но вопрос был не про find а про изменение ключа

всё верно. про изменение ключа в set, но не в map. Т.к. в map ключи константны. но на момент написания кода я не знал, как получить доступ к ключу. поэтому и использовал функцию find. это не принципиально важно. можно использовать вместо find итератор на начало:
Код
set<string>::iterator it = set1.begin();
cout << *it << endl;
*it = "life";
cout << *it << endl;


Цитата(azesmcar @  3.3.2009,  09:05 Найти цитируемый пост)
я уже привел цитату из стандарта и из журнала C++ Report. Этого мало?

В этой цитате говорится, что менять ключ нельзя, т.к. это может изменить относительную позицию в контейнере. Но если менять ключ так, чтобы его относительная позиция сохранялась, то изменять значения ключей можно. как и в map, так и в set.

Цитата(azesmcar @  3.3.2009,  09:05 Найти цитируемый пост)
а map притом что без разницы

есть разница в том, что Саттер smile пишет, что для map 100% определено, что ключи описаны как константные, а для случая set не всё так однозначно.


--------------------
PM MAIL   Вверх
azesmcar
Дата 3.3.2009, 09:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Цитата

есть разница в том, что Саттер пишет, что для map 100% определено, что ключи описаны как константные, а для случая set не всё так однозначно. 


я знаю что пишет Саттер, и видел что в стандарте ключь сета не описан как константный. Но это еще ничего не значит, стандарт тоже не идеален, потому существуют книги, журналы и тому подобное, в статье C++ report явно написано что ключь должен быть константным для любого ассоциативного контейнера. И Саттер тоже не мало запрещал делать то что позволяет стандарт. А почему студия не соответствует стандарту, смотрите пример.

Добавлено через 2 минуты и 20 секунд
Цитата

В этой цитате говорится, что менять ключ нельзя, т.к. это может изменить относительную позицию в контейнере. Но если менять ключ так, чтобы его относительная позиция сохранялась, то изменять значения ключей можно. как и в map, так и в set.


где это такое говорится?

Цитата

Once a key has been inserted into the container, that key had better not be changed in any way that would change its relative position in the container


по моему ясно написано.
PM   Вверх
zim22
Дата 3.3.2009, 10:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 29
Всего: 69



Цитата(azesmcar @  3.3.2009,  09:43 Найти цитируемый пост)
Once a key has been inserted into the container, that key had better not be changed in any way that would change its relative position in the container

Возможно я не правильно перевёл smile
Как только ключ был вставлен в контейнер, его лучше не изменять такими способами, которые меняли бы его относительную позицию в контейнере.

Из этого я делаю вывод, что если при изменении ключа его относительная позиция не изменится - то изменять его можно.

Добавлено через 5 минут и 7 секунд
Цитата(azesmcar @  3.3.2009,  09:28 Найти цитируемый пост)
получаем в результате1 2 1 4

В этом примере Вы умышленно изменили относительную позицию элемента в контейнере. 
Тем самым Вы сами берёте ответственность за порчу его структуры. Хотя и MSVC 2008 позволяет это делать smile

Код
 *it = 1;

я думаю в таких случаях необходимо явно указывать, что мы будем изменять ключ. т.е. с помощью const_cast приведения
Код

 std::set<int>::iterator it = t.find(3);
    
    const_cast<int&>(*it) = 1;


Это сообщение отредактировал(а) zim22 - 3.3.2009, 10:01


--------------------
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0632 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.