Форум программистов, компьютерный форум CyberForum.ru

Можно ли узнать размер одного элемента в STL контейнере? - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 10, средняя оценка - 4.80
diagon
Higher
 Аватар для diagon
1920 / 1186 / 49
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
23.04.2012, 10:53     Можно ли узнать размер одного элемента в STL контейнере? #1
Допустим, мне захотелось узнать, сколько памяти ест мой map. Для этого надо знать размер 1 элемента. Я погуглил, покопался в cpp-reference, но ничего полезного не нашел. Сойдут и нестандартные способы, кроме изучения исходников компилятора.
P.S. для примера
C++
1
std::map< int, int > map;
В этом примере кроме pair< int, int >, который вешает 8 байт, теоретически должны храниться еще 3 указателя, итого 1 элемент мапа на 64битной оси вешает [размер pair] + 24 байта, что довольно ощутимо, если map имеет большой размер. Но стандартом, насколько я знаю, реализация контейнеров не оговаривается, поэтому map может быть реализован более экономно. А вот проверить это я не могу =\
P.P.S. вопрос касается не только map, но и других контейнеров(к примеру, set тоже должен хранить 3 указателя). И еще unordered_map интересует.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
23.04.2012, 10:53     Можно ли узнать размер одного элемента в STL контейнере?
Посмотрите здесь:

C++ Как можно узнать размер выделенной динамической памяти, на которую ссылается указатель a?
C++ Позиция элемента в контейнере STL кон. SET, поиск контейнер set словарь позиция
C++ Какие подводные камни могут быть, при хранении в контейнере элемента типа void*?
C++ Наличие элемента в контейнере
C++ STL. Сортировка объектов в контейнере
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
23.04.2012, 12:07     Можно ли узнать размер одного элемента в STL контейнере? #2
Ну пример для gcc...

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <map>
#include <iostream>
 
int main()
{
   std::map<std::string, std::string> map =
   {
      std::make_pair("1", "1")
   };
   for (std::map<std::string, std::string>::iterator iter = map.begin(); iter != map.end(); ++iter)
   {
      std::cout << 
      sizeof(*reinterpret_cast<std::_Rb_tree_node
      <std::map<std::string, std::string>::value_type>*>(iter._M_node)) << std::endl;
   }
}
А вот, чтобы на любом компиляторе... Никак. А зачем это нужно?
fasked
Эксперт C++
 Аватар для fasked
4925 / 2505 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
24.04.2012, 08:08     Можно ли узнать размер одного элемента в STL контейнере? #3
Ребят, объясните мне, пожалуйста, что это значит. В чем грандиозность задумки.
Я имею в виду, почему просто не:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <map>
#include <vector>
#include <iostream>
 
int main()
{
   std::map<int, short> map =
   {
      std::make_pair(1, 1),
      std::make_pair(2, 2)
   };
      
   std::cout << sizeof(map) + sizeof(*map.begin()) * map.size() << std::endl;
   
   std::vector<unsigned char> vector =
   {
      1, 2, 3
   };
   
   std::cout << sizeof(vector) + sizeof(*vector.begin()) * vector.capacity() << std::endl;
}
diagon
Higher
 Аватар для diagon
1920 / 1186 / 49
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
24.04.2012, 08:20  [ТС]     Можно ли узнать размер одного элемента в STL контейнере? #4
В случае с вектором никакой разницы нету, т.к. он реализован просто в виде С-массива.
Но, к примеру, в одном элементе list'a хранятся указатели на предыдущий и следующий элемент, и здесь
C++
1
sizeof(*mylist.begin())
они не учитываются.
Если верить Саттеру, то в одном элементе set/map хранится уже 3 указателя(на предыдущий элемент, на следующий элемент и на родителя), и я просто хотел это проверить, ибо книга уже слегка устарела(например, там говорится, что vector<bool> медленнее, чем vector<int>).
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
24.04.2012, 08:49     Можно ли узнать размер одного элемента в STL контейнере? #5
fasked, Одного элемента. Не всего контейнера а одного элемента в контейнере. Причем не value_type-а, а по внутренней реализации. Допустим для списка:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    struct _List_node_base
    {
      _List_node_base* _M_next;
      _List_node_base* _M_prev;
      
      static void
      swap(_List_node_base& __x, _List_node_base& __y) throw ();
      
      void
      _M_transfer(_List_node_base* const __first,
          _List_node_base* const __last) throw ();
      
      void
      _M_reverse() throw ();
      
      void
      _M_hook(_List_node_base* const __position) throw ();
      
      void
      _M_unhook() throw ();
    };
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /// An actual node in the %list.
  template<typename _Tp>
    struct _List_node : public __detail::_List_node_base
    {
      ///< User's data.
      _Tp _M_data;
 
#ifdef __GXX_EXPERIMENTAL_CXX0X__
      template<typename... _Args>
        _List_node(_Args&&... __args)
    : __detail::_List_node_base(), _M_data(std::forward<_Args>(__args)...) 
        { }
#endif
    };
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  /// See bits/stl_deque.h's _Deque_base for an explanation.
  template<typename _Tp, typename _Alloc>
    class _List_base
    {
    protected:
      // NOTA BENE
      // The stored instance is not actually of "allocator_type"'s
      // type.  Instead we rebind the type to
      // Allocator<List_node<Tp>>, which according to [20.1.5]/4
      // should probably be the same.  List_node<Tp> is not the same
      // size as Tp (it's two pointers larger), and specializations on
      // Tp may go unused because List_node<Tp> is being bound
      // instead.
      //
      // We put this to the test in the constructors and in
      // get_allocator, where we use conversions between
      // allocator_type and _Node_alloc_type. The conversion is
      // required by table 32 in [20.1.5].
      typedef typename _Alloc::template rebind<_List_node<_Tp> >::other
        _Node_alloc_type;
 
      typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type;
 
      struct _List_impl 
      : public _Node_alloc_type
      {
    __detail::_List_node_base _M_node;
 
    _List_impl()
    : _Node_alloc_type(), _M_node()
    { }
 
    _List_impl(const _Node_alloc_type& __a)
    : _Node_alloc_type(__a), _M_node()
    { }
      };
 
      _List_impl _M_impl;
C++
1
2
  template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
    class list : protected _List_base<_Tp, _Alloc>

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  /**
   *  @brief A list::iterator.
   *
   *  All the functions are op overloads.
  */
  template<typename _Tp>
    struct _List_iterator
    {
      typedef _List_iterator<_Tp>                _Self;
      typedef _List_node<_Tp>                    _Node;
 
      typedef ptrdiff_t                          difference_type;
      typedef std::bidirectional_iterator_tag    iterator_category;
      typedef _Tp                                value_type;
      typedef _Tp*                               pointer;
      typedef _Tp&                               reference;
 
      _List_iterator()
      : _M_node() { }
 
      explicit
      _List_iterator(__detail::_List_node_base* __x)
      : _M_node(__x) { }
 
      // Must downcast from _List_node_base to _List_node to get to _M_data.
      reference
      operator*() const
      { return static_cast<_Node*>(_M_node)->_M_data; }
 
      pointer
      operator->() const
      { return std::__addressof(static_cast<_Node*>(_M_node)->_M_data); }
 
      _Self&
      operator++()
      {
    _M_node = _M_node->_M_next;
    return *this;
      }
 
      _Self
      operator++(int)
      {
    _Self __tmp = *this;
    _M_node = _M_node->_M_next;
    return __tmp;
      }
 
      _Self&
      operator--()
      {
    _M_node = _M_node->_M_prev;
    return *this;
      }
 
      _Self
      operator--(int)
      {
    _Self __tmp = *this;
    _M_node = _M_node->_M_prev;
    return __tmp;
      }
 
      bool
      operator==(const _Self& __x) const
      { return _M_node == __x._M_node; }
 
      bool
      operator!=(const _Self& __x) const
      { return _M_node != __x._M_node; }
 
      // The only member points to the %list element.
      __detail::_List_node_base* _M_node;
    };
Итого. Каждый элемент это _List_node_base, а если точнее _List_node<T>.
Каждый элемент списка занимает 8 + sizeof(T) байт на 32-битной машине.
Проверка.

C++
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <list>
 
int main()
{
   std::list<int> lst = {1};
   std::list<int>::iterator iter = lst.begin();
   std::cout << "Sizeof 1 element: " << 
      sizeof(*reinterpret_cast<std::_List_node<int>*>(iter._M_node)) << std::endl;
}
http://liveworkspace.org/code/fd33c1...334c50144bfbc7
Yandex
Объявления
24.04.2012, 08:49     Можно ли узнать размер одного элемента в STL контейнере?
Ответ Создать тему
Опции темы

Текущее время: 01:38. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru