Область действия записи, добавленной в набор С++?

Допустим, у меня есть глобальный набор, определенный следующим образом:

std::set<Person> people;

У меня также есть функция, в которой я создаю экземпляр класса Person и добавляю его в набор следующим образом:

void addEntry() {
    Person p1("kosh", 55);
    people.emplace(p1);
}

Насколько я понимаю, будет создана копия объекта (я вижу, как вызывается конструктор копирования) и добавлена ​​в набор. Как только эта функция завершается, p1 выходит за пределы области действия. Но каков объем копии, добавляемой в набор? Это определяется объемом набора?

РЕДАКТИРОВАТЬ 1:

Последующий вопрос: В таком случае лучше просто создать p1 в куче, а не в стеке, и сохранить указатель в наборе?

Пожалуйста, не задавайте несколько вопросов в одном сообщении. Если у вас есть еще дополнительные вопросы, задайте их отдельно.

Remy Lebeau 23.05.2024 22:49

вы почти никогда не захотите хранить указатели в стандартных контейнерах. Указатели нужны для хранения полиморфных объектов и в некоторых других случаях, но не здесь.

463035818_is_not_an_ai 23.05.2024 22:52

Будет ли что-то «лучше» всегда зависит от ваших потребностей. Наборы даже не перемещают свои элементы, поэтому некоторые причины хранить указатели (по какой-то причине дорогостоящие перемещения или желание сохранить постоянные указатели this) неприменимы. Тем не менее, std::unordered_map<std::string, std::unique_ptr<ItemBase>> children; — здесь мы ссылаемся на базовый класс, который может быть разными реальными классами. std::unordered_map<PackageID, std::shared_ptr<const LicenseInfo>> licenses; -- здесь объекты могут сохраняться за пределами их присутствия на карте.

Christian Stieber 23.05.2024 22:53

«область действия» применяется к переменным. Что касается ценностей, вопрос должен стоять о «сроке жизни».

Barmar 23.05.2024 22:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Но каков объем копии, добавляемой в набор? Это определяется объемом набора?

Да. Скопированный объект хранится внутри объекта set и будет уничтожен при очистке или уничтожении set. Если только вы не erase() заранее введете копию.

В таком случае лучше просто создать p1 в куче, а не в стеке, и сохранить указатель в наборе?

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

Более простым вариантом было бы просто не передавать объект в emplace() для его копирования. Вы можете передать нужные параметры конструктора Person непосредственно в emplace(), и он создаст для вас объект Person, например:

void addEntry() {
    people.emplace("kosh", 55);
}
Ответ принят как подходящий

Срок службы и объем

Время жизни объекта — это отрезок времени во время выполнения программы, в течение которого объект активен и к нему можно получить доступ.

Область действия — это места в коде, из которых может быть осуществлен такой доступ. Смотрите также:

Область действия и время жизни переменной

Срок жизни объекта в наборе

Вы вызываете метод emplace() набора со ссылкой на локальную переменную.

Что делает emplace(t)? Его функция довольно одинакова для разных коллекций:

emplace(t): Создайте новый объект внутри контейнера как копию объекта t.

(I've simplified things bit, e.g. w.r.t. move semantics)

Итак, вы на самом деле не кладете t внутрь контейнера. Вы создаете другой объект; а контейнеры, такие как std::set(), реализованы так, что время жизни созданного элемента будет фактически таким же, как и у контейнера.

Примечания:

  • Ответ Реми Лебо правильный, я просто хотел сосредоточиться на используемом методе.
  • Обратите внимание, что std::set предназначен для упорядоченных элементов; математическое понятие набора лучше отражается с помощью std::unordered_set.

Последующий вопрос: стоит ли использовать указатели?

лучше просто создать p1 в куче, а не в стеке, и сохранить указатель в наборе?

Почему это было бы лучше? ... Я полагаю, вы бы сказали, что избегайте создания двух Person.

Ну, а вообще, попробуйте что-нибудь другое: вообще не создавайте p1; просто emplace() используя аргументы конструктора Person класса, и тогда никогда не будет никакого объекта, кроме того, который создан внутри набора. Таким образом, создается и затем используется только один экземпляр Person.

Другие вопросы по теме