Динамические против нединамических членов класса - PullRequest
5 голосов
/ 26 июля 2010

В C ++, если у меня есть класс, который должен содержать член, который может быть динамически выделен и использован в качестве указателя, или нет, например:

class A {
    type a;
};

или

class A {
    A();
    ~A();
    type* a;
};

и в конструкторе:

A::A {
    a = new type();
}

и деструктор:

A::~A {
    delete a;
}

Есть ли какие-либо преимущества или недостатки у одного из них, кроме динамического, требующего больше кода? Они ведут себя по-разному (кроме разыменования указателя) или один медленнее другого? Какой из них я должен использовать?

Ответы [ 6 ]

5 голосов
/ 26 июля 2010

Есть несколько отличий:

  1. Размер каждого члена должен быть известен при определении класса. Это означает, что вы должны включить заголовок type, и вы не можете просто использовать forward-декларацию, как если бы вы использовали член-указатель (так как размер всех указателей известен). Это имеет значение для #include беспорядка и времени компиляции для больших проектов.

  2. Память для члена данных является частью экземпляра включающего класса, поэтому он будет выделен в то же время, в том же месте, что и все остальные члены класса (будь то на стек или куча). Это имеет значение для локальности данных - размещение всего в одном месте потенциально может привести к лучшему использованию кэша и т. Д. Распределение стека, вероятно, будет немного быстрее, чем выделение кучи. Объявление слишком большого количества экземпляров огромных объектов может ускорить ваш стек.

  3. Тип указателя сложнее управлять - поскольку он не выделяется и не уничтожается автоматически вместе с классом, вам необходимо убедиться, что вы делаете это самостоятельно. Это становится сложно с несколькими членами-указателями - если вы все их используете в конструкторе, и в середине процесса есть исключение, деструктор не вызывается, и у вас есть утечка памяти. Лучше назначить переменные-указатели для контейнера «умного указателя» (например, std::auto_ptr) немедленно , таким образом, очистка будет выполняться автоматически (и вам не нужно беспокоиться о delete их вводе в деструктор, часто спасает вас от написания одного). Кроме того, каждый раз, когда вы обрабатываете ресурсы вручную, вам нужно беспокоиться о конструкторах копирования и операторах присваивания.

0 голосов
/ 27 июля 2010

Если переменная-член должна жить дольше срока жизни объекта, или если ее владение должно быть передано другому объекту, то член должен динамически (куча) выделяться с использованием «new» Если это не так, то зачастую лучше сделать его прямым членом класса, чтобы упростить код и уменьшить нагрузку на распределитель памяти. Выделение памяти стоит дорого.

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

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

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

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

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

Основное отличие состоит в том, что указатель потенциально может указывать куда-то еще.

редактировать

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

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

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

С точки зрения производительности, использование указателя означает большее использование памяти, большую фрагментацию памяти и разыменование требует времени,Однако для всего, кроме самого критичного для производительности кода, об этом не стоит беспокоиться.

...