В чем разница и преимущества этих двух строк кода? - PullRequest
4 голосов
/ 26 июля 2011

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

Вот две структуры в качестве примера:

struct Employee 
{
    std::string firstname, lastname;
    char middleInitial;
    Date hiringDate; // another struct, not important for example
    short department;
};

struct Manager
{
    Employee emp; // manager employee record
    list<Employee*>group; // people managed
};

Что лучше использовать из этих двух в приведенной выше структуре и почему?

list<Employee*>group;
list<Employee>group;

Ответы [ 9 ]

6 голосов
/ 26 июля 2011

Прежде всего, std::list - это двусвязный список.Таким образом, оба этих заявления создают связанный список сотрудников.

list<Employee*> group;

Это создает список указателей на Employee объектов .В этом случае должен быть какой-то другой код для распределения каждого сотрудника, прежде чем вы сможете добавить его в список.Точно так же каждый сотрудник должен быть удален отдельно, std :: list не сделает этого за вас.Если список сотрудников будет передан какой-либо другой организации, это будет иметь смысл.Вероятно, было бы лучше поместить сотрудника в класс интеллектуальных указателей, чтобы предотвратить утечки памяти.Что-то вроде

typedef std::list<std::shared_ptr<Employee>> EmployeeList;
EmployeeList group;

Эта строка

list<Employee>group;

создает список Employee объектов по значению .Здесь вы можете создавать объекты Employee в стеке, добавлять их в список и не беспокоиться о распределении памяти.Это имеет смысл, если список сотрудников не доступен никому другому.

1 голос
/ 26 июля 2011

Многое зависит от того, что вы делаете. Для начала, ты действительно хочешь Manager, чтобы содержать Employee, а не быть одним: классический Пример менеджера (один из классических примеров ОО) будет:

struct Manager : public Employee
{
    list<Employee*> group;
};

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

Второй момент заключается в том, что для принятия разумного решения вы должны понимать роль Employee в программе. Если Employee это просто значение: некоторые жесткие данные, как правило, неизменяемые (за исключением присваивание полного Employee), тогда list<Employee> group безусловно, чтобы быть предпочтительным: не используйте указатели, если вам не нужно. Если Employee является «сущностью», которая моделирует некоторую внешнюю сущность (скажем, сотрудника фирмы), вы, как правило, сделаете нельзя назначить и использовать list<Employee*> (с каким-то механизмом для сообщите Manager, когда сотрудник уволен, и объект удален). Если менеджеры являются сотрудниками, а вы не хотите потерять этот факт, когда они добавляются в группу, то вы должны использовать версия указателя: полиморфизм требует указателей или ссылок для работы (и у вас не может быть контейнера ссылок).

1 голос
/ 26 июля 2011

Первый хранит объекты по указателю.В этом случае вам необходимо тщательно задокументировать, кому принадлежит выделенная память и кто отвечает за ее очистку после завершения.Второй хранит объекты по значению и имеет полный контроль над их продолжительностью жизни.

Какой из них использовать, зависит от контекста, который вы не задали в своем вопросе, хотя я предпочитаю второй немного по умолчанию, поскольку он не 't оставьте открытой возможность неправильного управления вашей памятью.

Но после всего этого, тщательно подумайте, действительно ли list является правильным выбором контейнера для вас.Обычно это контейнер с низким приоритетом, который удовлетворяет очень специфическим потребностям.Я почти всегда предпочитаю vector и deque сначала для контейнеров с произвольным доступом, или set и map для заказанных контейнеров.

Если вам нужно хранить указатели в контейнере, boost предоставляет ptr-Контейнерные классы, которые управляют памятью для вас, или Я предлагаю сохранить какой-нибудь интеллектуальный указатель, чтобы память очищалась автоматически, когда объект больше не нужен.

1 голос
/ 26 июля 2011

Два списка хороши, но требуют совершенно другой обработки.

list<Employee*>group;

- это список указателей на объекты типа Employee, и вы будете хранить там указатели на объекты, размещенные динамически, и вам нужно будет особенно четко определить, кто будет удалять эти объекты.

list<Employee>group;

- список объектов типа Employee; вы получаете выгоду (и связанные с этим затраты с точки зрения производительности) от работы с конкретными случаями, когда вам не нужно управлять памятью самостоятельно.

В частности, одним из преимуществ использования std::list по сравнению с обычным массивом является то, что вы можете иметь список объектов и избежать затрат и рисков, связанных с динамическим выделением памяти и указателями.

Со списком объектов вы можете сделать, e. г.

Employee a;    // object allocated in the stack
list.push_back(a); // the list does a copy for you

Employee* b = new Employee....
list.push_back(*b); // the object pointed is copied
delete b;

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

Используя указатели std :: list, вы более или менее находитесь в той же ситуации, что и при использовании простого массива указателей в том, что касается управления памятью. Единственное преимущество, которое вы получаете, заключается в том, что список может динамически увеличиваться без усилий с вашей стороны.

Лично я не вижу большого смысла в использовании списка указателей; в основном, потому что я думаю, что указатели должны использоваться (всегда, когда это возможно) через умные указатели . Так что, если вам действительно нужны указатели, вам, IMO, будет лучше, если использовать список умных указателей, предоставленных boost.

1 голос
/ 26 июля 2011

Возможно, вы захотите использовать второй, если вы сохраняете «людей, которым удалось», чтобы их можно было сохранить и в другом месте. Для уточнения: если у вас также есть глобальный список companyEmployees, вы, вероятно, хотите иметь указатели, так как вы хотите разделить объект, представляющий сотрудника, между местоположениями (так что, например, если вы обновите имя, изменение будет «видно» из обоих мест).

Если вместо этого вы хотите знать только «почему список структур вместо списка указателей», ответ таков: лучшая локальность памяти, нет необходимости перераспределять отдельные объекты Employee, но будьте осторожны при каждом назначении в / из узел списка (например, через итератор и его оператор *) копирует всю структуру, а не только указатель.

1 голос
/ 26 июля 2011

Один - это список указателей, а другой - список объектов.Если вы уже разместили объекты, первый имеет смысл.

0 голосов
/ 26 июля 2011

Вы, вероятно, хотите использовать unique_ptr <> или auto_ptr <> или shared_ptr <> вместо простых старых * указателей. Это идет, если не весь, путь к ожидаемому использованию без особых проблем с памятью при использовании объектов без кучи ...

0 голосов
/ 26 июля 2011

Первый определяет список указателей на объекты, второй - список объектов.
Первая версия (с указателями) предпочтительна для большинства программистов.Основная причина в том, что STL копирует элементы по значению, делая сортировку и внутреннее перераспределение более эффективными.

0 голосов
/ 26 июля 2011

Используйте первый, если вы выделяете или получаете доступ к структурам отдельно.

Используйте второй, если вы будете только выделять / получать к ним доступ через список.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...