STL вставка первого элемента в контейнер std::map
От: Virtus  
Дата: 28.04.11 18:01
Оценка:
Доброго времени суток!
Возник такой вопрос:
Есть контейнер map, в качестве ключа тип int, значения другой map:
std::map< int, std::map< int, CCellInfo*> >
При вставке элемента в контейнер (ключ не существует для "внешнего" map) получается вставить его
только с помощью оператора[], так как не могу создать "вложенный" map, чтобы использовать insert().
Когда же элемент "внешнего" map вставлен (такой ключ уже существует), то можно использовать итератор
"внешнего" и использовать для "вложенного" insert(). Можно ли в такой ситуации не использовать
оператор[]?

 class CCellCell {
   public :
     bool SetSubItemInfo( int nItem, int nSubItem, CCellInfo::eType nType );
     typedef std::map< int, CCellInfo*, std::less< int > > mapSubItem;
     typedef std::pair< int, CCellInfo* >                  pairSubItem;
     typedef mapSubItem::iterator                          itSubItem;
     typedef std::map< int, mapSubItem, std::less< int > > mapItem;
     typedef std::pair< int, mapSubItem >                  pairItem;
     typedef mapItem::iterator                             itItem;
     mapItem                                               m_mapItem;
 };

 bool CCellCell::SetSubItemInfo( int nItem, int nSubItem, CCellInfo::eType nType )
 {
   itItem it = m_mapItem.find( nItem );
   if ( it == m_mapItem.end() ) {

// ключ не существует //
// 1. все работает //
     m_mapItem[nItem][nSubItem] = new CCellInfo(nType);
     return ( true );

// 2. ошибка компиляции - неверный 2-ой аргумент (вместо mapSubItem - pairSubItem)
     return ( (m_mapItem.insert(pairItem(nItem, pairSubItem(nSubItem, new CCellInfo(nType))))).second );

// 3. компилируется, ошибка времени выполнения
     mapSubItem map;
     map.insert( pairSubItem(nSubItem, new CCellInfo(nType)));
     m_mapItem.insert(pairItem(nItem, map));
     return ( true );

    }

// ключ существует //
   itSubItem pos = (it->second).find( nSubItem );

   if ( pos != (it->second).end() ) {
     delete ( pos->second );
     (it->second).erase( pos );
     }

   return ( ((it->second).insert(pairSubItem(nSubItem, new CCellInfo(nType)))).second );
 }
Re: STL вставка первого элемента в контейнер std::map
От: uzhas Ниоткуда  
Дата: 28.04.11 20:59
Оценка:
Здравствуйте, Virtus, Вы писали:

V>Доброго времени суток!

я не увидел разницу между вариантом 1 и 3
покажите где у вас возникает "ошибка времени выполнения"
вот вам холст http://ideone.com/GLop4
Re: STL вставка первого элемента в контейнер std::map
От: rg45 СССР  
Дата: 29.04.11 04:08
Оценка: 1 (1)
Здравствуйте, Virtus, Вы писали:

V>При вставке элемента в контейнер (ключ не существует для "внешнего" map) получается вставить его

V>только с помощью оператора[], так как не могу создать "вложенный" map, чтобы использовать insert().

Почему не можешь? operator[] именно это и делает:
23.3.1.2 map element access
T& operator[](const key_type& x);
1 Returns: (*((insert(make_pair(x, T()))).first)).second.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: STL вставка первого элемента в контейнер std::map
От: Virtus  
Дата: 29.04.11 10:13
Оценка: :)
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, Virtus, Вы писали:


V>>Доброго времени суток!

U>я не увидел разницу между вариантом 1 и 3
U>покажите где у вас возникает "ошибка времени выполнения"
U>вот вам холст http://ideone.com/GLop4

// 3. компилируется, ошибка времени выполнения
     mapSubItem map;
     map.insert( pairSubItem(nSubItem, new CCellInfo(nType)));
     m_mapItem.insert(pairItem(nItem, map));
     return ( true );


Спасибо, посмотрел Ваш пример — вариант работает.
У меня тоже заработал этот вариант. Похоже, возврат из функции закомментирован был.
Re[2]: STL вставка первого элемента в контейнер std::map
От: Virtus  
Дата: 29.04.11 11:24
Оценка:
Здравствуйте, rg45, Вы писали:

R>Почему не можешь? operator[] именно это и делает:

R>
R>23.3.1.2 map element access
R>T& operator[](const key_type& x);
R>1 Returns: (*((insert(make_pair(x, T()))).first)).second.
R>


Посмотрел реализацию operator[].

 // оператор[]
 T& operator[]( const key_type& x ) {
  return ( (*((insert(make_pair(x, T()))).first)).second );
 }

 pair <iterator, bool> <- insert(make_pair(x, T()))                       // возвращает пару : итератор, результат вставки
              iterator <- ((insert(make_pair(x, T()))).first)             // возвращает итератор
             *iterator <- (*((insert(make_pair(x, T()))).first))          // возвращает содержимое итератора
                    T& <- ((*((insert(make_pair(x, T()))).first)).second) // возвращает по итератору ссылку на значение по ключю

 // применительно к моему случаю 
 pair <iterator, bool> <- mapSubItem::insert(pairSubItem(nSubItem, new CCellInfo(nType)));
              iterator <- ((mapSubItem::insert(pairSubItem(nSubItem, new CCellInfo(nType)))).first);
             *iterator <- (*((mapSubItem::insert(pairSubItem(nSubItem, new CCellInfo(nType)))).first));


Но, похоже, не получится одним выражением и без локального "вложенного" map:

 // Вместо:
 m_mapItem[nItem][nSubItem] = new CCellInfo( nType );
 return ( true );

 // Делаю так:
 mapSubItem map;
 return ( (m_mapItem.insert(
               pairItem(nItem, (*((map.insert(pairSubItem(nSubItem, new CCellInfo(nType)))).first)))
                           )).second );


Ошибка: вместо pair< int, mapSubItem > получается pair< int, *iterator >
Re: STL вставка первого элемента в контейнер std::map
От: XuMuK Россия  
Дата: 29.04.11 14:04
Оценка: 1 (1)
Здравствуйте, Virtus, Вы писали:

V>Доброго времени суток!

V>Возник такой вопрос:
V>Есть контейнер map, в качестве ключа тип int, значения другой map:
V>std::map< int, std::map< int, CCellInfo*> >
V>При вставке элемента в контейнер (ключ не существует для "внешнего" map) получается вставить его
V>только с помощью оператора[], так как не могу создать "вложенный" map, чтобы использовать insert().
V>Когда же элемент "внешнего" map вставлен (такой ключ уже существует), то можно использовать итератор
V>"внешнего" и использовать для "вложенного" insert(). Можно ли в такой ситуации не использовать
V>оператор[]?

можно:

  typedef std::map<int, std::map<int, CCellInfo*> > collection_t;
  typedef collection_t::mapped_type subcollection_t;
  collection_t _m;

  bool insert(int k1, int k2)
  {
    // используем уже существующуй вложенный мап, если k1 есть во внешнем мапе или создаем пустой вложенный мап
    collection_t::iterator it = _m.insert(collection_t::value_type(k1, subcollection_t())).first;
    // вставляем элемент во вложенный мап
    std::pair<subcollection_t::iterator, bool> result = it->second.insert(subcollection_t::value_type(k2, 0));
    // создаем новый объект, если его не было во вложенном мапе
    if (result.second)
      result.first->second = new CCellInfo();
    return result.second;
  }
Re: STL вставка первого элемента в контейнер std::map
От: Alexander G Украина  
Дата: 30.04.11 10:10
Оценка: 1 (1)
Может, удобнее через один map ?

typedef std::pair< int, int >                        mapKey
typedef std::map< mapKey, mapSubItem >               mapItem;
mapItem                                              m_mapItem;

bool SetSubItemInfo( int nItem, int nSubItem, CCellInfo::eType nType )
{
  CCellInfo * p = new CCellInfo(nType);
  bool result = m_mapItem.insert( std::make_pair(nItem, nSubItem), p);
  if ( ! result  )
  {
    delete p;
  }
  return result;
}
Русский военный корабль идёт ко дну!
Re[2]: STL вставка первого элемента в контейнер std::map
От: XuMuK Россия  
Дата: 03.05.11 10:22
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Может, удобнее через один map ?


AG>
AG>typedef std::pair< int, int >                        mapKey
AG>typedef std::map< mapKey, mapSubItem >               mapItem;
AG>mapItem                                              m_mapItem;

AG>bool SetSubItemInfo( int nItem, int nSubItem, CCellInfo::eType nType )
AG>{
AG>  CCellInfo * p = new CCellInfo(nType);
AG>  bool result = m_mapItem.insert( std::make_pair(nItem, nSubItem), p);
AG>  if ( ! result  )
AG>  {
AG>    delete p;
AG>  }
AG>  return result;
AG>}
AG>


Лучше вставлять лучше 0, а не новый элемент, чтобы не делать бесполезную работу по созданию/удалению объектов при вставке.
Re[2]: STL вставка первого элемента в контейнер std::map
От: Virtus  
Дата: 04.05.11 08:41
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Может, удобнее через один map ?


AG>
AG>typedef std::pair< int, int >                        mapKey
AG>typedef std::map< mapKey, mapSubItem >               mapItem;
AG>mapItem                                              m_mapItem;

AG>bool SetSubItemInfo( int nItem, int nSubItem, CCellInfo::eType nType )
AG>{
AG>  CCellInfo * p = new CCellInfo(nType);
AG>  bool result = m_mapItem.insert( std::make_pair(nItem, nSubItem), p);
AG>  if ( ! result  )
AG>  {
AG>    delete p;
AG>  }
AG>  return result;
AG>}
AG>


Спасибо, этот вариант красивее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.