Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.56/9: Рейтинг темы: голосов - 9, средняя оценка - 4.56
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712

Добавление своего типа данных в map

04.12.2019, 15:36. Показов 2005. Ответов 18
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Приветствую всех. Сделал тестовый пример:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
class A
{
  public:
  A()  { cout << "A() " << endl;  }
  ~A() { cout << "~A() " << endl; }
};
 
int main()
{
  map<string, A> m;
  m.insert(make_pair<string, A>("one", A()));
  return 0;
}
Объясните, пожалуйста, почему при запуске кода конструктор выполняется один раз, деструктор 3 раза! Последний вызов деструктора понятен: контейнер m выходит за область видимости. Но откуда еще 2 деструктора и где относящиеся к ним конструкторы?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
04.12.2019, 15:36
Ответы с готовыми решениями:

Нужен совет по созданию своего типа данных
Приветствую всех. Мне необходимо создать свой тип данных &quot;Пароль&quot;. Размер самого пароля всегда один и тот же и составляет 6 байт. Кроме...

Передача в контейнер map пользовательского типа данных
Доброго времени суток, дамы и господа. Интересует такая задачка: создать контейнер типа map, который будет хранить пользовательский тип...

sort для своего типа данных
#include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;algorithm&gt; using namespace std; class foo { public: foo() : v(0)...

18
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
04.12.2019, 16:33
Цитата Сообщение от d7d1cd Посмотреть сообщение
Объясните, пожалуйста, почему при запуске кода конструктор выполняется один раз, деструктор 3 раза! Последний вызов деструктора понятен: контейнер m выходит за область видимости. Но откуда еще 2 деструктора и где относящиеся к ним конструкторы?
У тебя там объект перемещается несколько раз - сначала в std::pair, потом в map, на каждое перемещение отрабатывает деструктор

Добавлено через 1 минуту
Используй emplace, вместо insert
C++
1
m.emplace("one");
1
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
04.12.2019, 16:38  [ТС]
oleg-m1973, спасибо. Но есть проблема. У меня система, где у map нет метода emplace. Как быть в этом случае?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
04.12.2019, 16:43
Цитата Сообщение от d7d1cd Посмотреть сообщение
oleg-m1973, спасибо. Но есть проблема. У меня система, где у map нет метода emplace. Как быть в этом случае?
Делай как раньше, insert, там вроде всё нормально. Или тебя деструкторы смущают?
1
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
04.12.2019, 16:50  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Или тебя деструкторы смущают?
Дело в том, что на самом деле класс А не имеет конструктора по умолчанию. При создании объекта этого класса в конструктор передается имя файла и он его открывает, сохраняя идентификатор (соответственно, деструктор закрывает). При копировании в pair отработает деструктор и закроет файл. В результате, в конечном итоге, в map будет экземпляр класса А с идентификатором файла, который уже закрыт.
Не могу сообразить как выйти из этой ситуации...
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
04.12.2019, 17:00
Цитата Сообщение от d7d1cd Посмотреть сообщение
При копировании в pair отработает деструктор и закроет файл. В результате, в конечном итоге, в map будет экземпляр класса А с идентификатором файла, который уже закрыт.
Добавь конструктор перемещения, либо используй
C++
1
2
map<string, std::unique_ptr<A>> m;
m.insert(make_pair("one", std::unique_ptr<A>(new A())));
Добавлено через 1 минуту
Если unique_ptr тоже не поддерживается, сделай std::map<string, A*>, только не забывай удалять эти указатели

Добавлено через 1 минуту
Кстати, что у тебя за компилятор, может просто обновить его?
0
фрилансер
 Аватар для Алексей1153
6462 / 5670 / 1131
Регистрация: 11.10.2019
Сообщений: 15,105
04.12.2019, 18:14
в старых компиляторах можно попробовать поискать тут (в VS9 уже есть)

C++
1
2
3
#include <memory>
 
std::tr1::shared_ptr
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
05.12.2019, 08:41  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Добавь конструктор перемещения
Конструктор перемещения не доступен в моем компиляторе.

Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Если unique_ptr тоже не поддерживается, сделай std::map<string, A*>, только не забывай удалять эти указатели
unique_ptr нет. Удалять указатели... Не, не хочется применять такой вариант.

Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Кстати, что у тебя за компилятор, может просто обновить его?
За обновлением надо идти с поклоном к IBM. Работаю в системе IBM i со встроенным в нее компилятором. На этой странице используемый мной компилятор произошел от IBM XLC++. Но не все возможности перенес .

В общем, решил просто нормально запрограммировать свой класс, определив в нем не только конструктор по умолчанию, но и конструктор копирования и оператор присваивания копированием (правило трех). Так как объект класса управляет файлом, то при создании копии объекта эта копия должна управлять тем же файлом. Кроме этого, при удалении одного из объекта (оригинала или копии) необходимо учитывать, нет ли "в живых" другого объекта, который управляет тем же файлом.
Тогда можно будет спокойно использовать метод insert через make_pair.
0
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 1
05.12.2019, 08:55
make_pair<const string, A>("one", A())
1
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
05.12.2019, 10:52
Цитата Сообщение от d7d1cd Посмотреть сообщение
В общем, решил просто нормально запрограммировать свой класс, определив в нем не только конструктор по умолчанию, но и конструктор копирования и оператор присваивания копированием (правило трех). Так как объект класса управляет файлом, то при создании копии объекта эта копия должна управлять тем же файлом. Кроме этого, при удалении одного из объекта (оригинала или копии) необходимо учитывать, нет ли "в живых" другого объекта, который управляет тем же файлом.
Тогда можно будет спокойно использовать метод insert через make_pair.
Лучше сделай указатели.
А ещё лучше, напиши свой класс, аналог shared_ptr, он довольно простой и решит все твои проблемы
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
05.12.2019, 11:40  [ТС]
Croessmah, добавление const избавило от одной пары конструктор копирования - деструктор. Спасибо.

Теперь столкнулся с другой проблемой.
Если обратиться в контейнере к существующему в нем элементу по ключу, то происходит вызов конструктора по умолчанию (без этого конструктора код обращения к элементу вообще не компилится), затем конструктора копирования, затем два раза деструктор.
Все усложняет еще то, что этот же код в онлайн компиляторе работает без вызова конструкторов и деструкторов при обращении к элементу.
Можете объяснить, что в моей STL библиотеке не так?

Тестируемый код:
Кликните здесь для просмотра всего текста
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
#include <iostream>
#include <string>
#include <map>
using namespace std;
 
 
class IFile
{
  public:
  IFile();
  IFile(const IFile&);
  ~IFile();
};
 
IFile::IFile() {
  cout << "IFile()" << endl;
}
 
IFile::IFile(const IFile&) {
  cout << "IFile(const IFile& iFile)" << endl;
}
 
IFile::~IFile() {
  cout << "~IFile()" << endl;
}
 
 
 
int main()
{
  cout << "Начало программы --------------------------------------------------" << endl;
  map<string, IFile> Files;
  const char* File = "one";
 
  cout << "Files.insert(make_pair<const string, IFile>(File, IFile())); ------" << endl;
  Files.insert(make_pair<const string, IFile>(File, IFile()));
 
  cout << "Files[File]; ------------------------------------------------------" << endl;
  Files[File];
 
  cout << "Files.clear(); ----------------------------------------------------" << endl;
  Files.clear();
 
  cout << "Конец программы ---------------------------------------------------" << endl;
  return 0;
}


Результат моего компилятора:
Кликните здесь для просмотра всего текста
Начало программы --------------------------------------------------
Files.insert(make_pair<const string, IFile>(File, IFile())); ------
IFile()
IFile(const IFile& iFile)
IFile(const IFile& iFile)
~IFile()
~IFile()
Files[File]; ------------------------------------------------------
IFile()
IFile(const IFile& iFile)
~IFile()
~IFile()
Files.clear(); ----------------------------------------------------
~IFile()
Конец программы ---------------------------------------------------


Результат онлайн компилятора (тип компилятора выбран С++):
Кликните здесь для просмотра всего текста
Начало программы --------------------------------------------------
Files.insert(make_pair<const string, IFile>(File, IFile())); ------
IFile()
IFile(const IFile& iFile)
IFile(const IFile& iFile)
~IFile()
~IFile()
Files[File]; ------------------------------------------------------
Files.clear(); ----------------------------------------------------
~IFile()
Конец программы ---------------------------------------------------
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
05.12.2019, 11:43
Цитата Сообщение от d7d1cd Посмотреть сообщение
Если обратиться в контейнере к существующему в нем элементу по ключу, то происходит вызов конструктора по умолчанию (без этого конструктора код обращения к элементу вообще не компилится), затем конструктора копирования, затем два раза деструктор.
Потому что здесь, если элемент не найден, то он создаётся. Используй для поиска метод find
0
фрилансер
 Аватар для Алексей1153
6462 / 5670 / 1131
Регистрация: 11.10.2019
Сообщений: 15,105
05.12.2019, 11:46
d7d1cd, у make_pair можно не указывать параметры шаблона, он их выведет

C++
1
m.insert(std::make_pair("one", A()));
насчёт лишних конструкторов и деструкторов - в дебаге всё "честно" вызывается, но в релизе компилятор пооптимизирует, не будет лишноты. Однако, если ты выводишь всякие дебажные сообщения в конструкторе и деструкторе, то оптимизатор может их и не убрать

Наверное, в онлайн компиляторе тоже оптимизатор поработал
0
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 1
05.12.2019, 11:58
Цитата Сообщение от Алексей1153 Посмотреть сообщение
у make_pair можно не указывать параметры шаблона, он их выведет
В данном случае он их выведет не так как нужно.
Цитата Сообщение от d7d1cd Посмотреть сообщение
В общем, решил просто нормально запрограммировать свой класс
Вы можете в IFile добавить счетчик ссылок.
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
05.12.2019, 12:25  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Потому что здесь, если элемент не найден, то он создаётся.
oleg-m1973, два вопроса:
1. Вы внимательно прочитали сообщение?
Цитата Сообщение от d7d1cd Посмотреть сообщение
Если обратиться в контейнере к существующему в нем элементу
2. Вы смотрели приведенный мной код?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
05.12.2019, 12:30
Цитата Сообщение от d7d1cd Посмотреть сообщение
oleg-m1973, два вопроса:
1. Вы внимательно прочитали сообщение?
Сообщение от d7d1cd
Я тебе написал, когда должен вызываться этотконструктор, для существующих элементов это вызова быть не должно. Что там делает твой говённый компилятор в своей библиотеке, я не знаю. Посмотри код оператора []
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
05.12.2019, 12:33  [ТС]
Цитата Сообщение от Croessmah Посмотреть сообщение
Вы можете в IFile добавить счетчик ссылок.
Так и планировал сделать.

Частично разобрался почему при обращении к существующему элементу вызываются конструкторы. Все из-за того, что в моей реализации STL оператор [] вызывает метод insert (что даже указано в справке) без предварительной проверки на существование элемента. Естественно, метод insert требует сконструированный объект.
0
285 / 176 / 21
Регистрация: 16.02.2018
Сообщений: 666
05.12.2019, 15:14
Цитата Сообщение от Croessmah Посмотреть сообщение
make_pair<const string, A>("one", A())
m["one"];
0
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 1
05.12.2019, 15:18
rat0r, параметры конструктора опущены. Выше ТС написал
Цитата Сообщение от d7d1cd Посмотреть сообщение
Дело в том, что на самом деле класс А не имеет конструктора по умолчанию.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
05.12.2019, 15:18
Помогаю со студенческими работами здесь

Использование vector insert и своего типа данных
Не понимаю почему вот здесь выскакивает странная ошибка: arr.insert(arr.begin(),(*max)); #include &lt;iostream&gt; #include...

Как использовать stl для своего класса(для пользовательского типа данных)
Мне бы пример какой-нибудь а то в инете ищу ничего не могу найти, кроме базовых типов данных

Можно ли реализовать Map от своего класса?
Надо сделать что-то подобное, подскажите возможно ли такое и как? public class Main { public static void main(String args) { ...

Добавление данных типа string в список
Здравствуйте! Хочу добавлять из файла слова в список, но возникают проблемы с Parse строки. Подскажите ,пожалуйста, как это сделать и...

добавление в map
Добрый день Задача такая, я считываю из бд данные и сохраняю их в map&lt;string, int&gt;. map хранит, в себе забаненый ip и его timestamp,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Новые блоги и статьи
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это дополнительная запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru