2010-07-08 3 views
5

У меня есть класс A, который состоит из объектов B и C. Как написать конструктор A, который получает объекты B и C? Должен ли я передавать их по значению, по ссылке (const) или указателю? Где я должен их освободить?Как передать параметры конструктору?

Я думал об указателях, потому что тогда я мог бы написать:

A a(new B(1,2,3,4,5), new C('x','y','z')) 

Но я не знаю, является ли это хорошая практика, или нет. Какие-либо предложения?

+1

См. [_Как передать объекты в функции на C++? _] (Http://stackoverflow.com/questions/2139224/how-to-pass-objects-to-functions-in-c/2139254#2139254) – sbi

ответ

7

Обычно вы проходите мимо константной ссылке:

A a(B(1,2,3,4,5), C('x','y','z')) 

Нет необходимости для указателей здесь.

Обычно вы сохраняете значения, если копирование слишком неэффективно. Определение класса затем читает:

class A { 
private: 
    B b; 
    C c; 
public: 
    A(const B& b, const C& c): b(b), c(c) { } 
}; 
2

Что вы передаете в зависимости от ваших потребностей.

Вам нужна копия вещи, в которой вы проходите? Затем передайте const-reference.

struct A 
{ 
    A(const B& b, const C& c) : m_b(b), m_c(c) {} 

private: 
    B m_b; 
    C m_c; 
}; 

И построить его так:

A myA(B(1,2,3), C(4,5,6)); 

Если вы хотите, чтобы ваш A объекта для обозначения некоторых других B и C объектов (но не владеть ими), а затем использовать указатели (или, возможно, ссылку).

+0

Я хочу, чтобы он владел ими, так что это не так. Спасибо вам все равно :) – mik01aj

+1

У вас есть потребность в динамически выделенных объектах? Else ** это ** ваш случай. Образец кода представляет собой самое простое из самых естественных решений на C++ при работе с композицией. –

+0

Я имел в виду последнее предложение. Я собираюсь использовать ссылки на const, поскольку большинство людей здесь предложили. – mik01aj

4

Должен ли я передавать их по значению по ссылке (const) или указателю?

  1. По константной ссылке, если объект большой
  2. по значению, если объект мал
  3. по константной указателя, если это необязательный аргумент, который может быть равен нулю (т.е. «NULL»)
  4. по указатель, если он является необязательным аргументом, который может быть нолем, но будет принадлежать (т.е. освобожден) построенным классом.

Обратите внимание, что если ваш класс имеет внутренние экземпляры B и C, то передача их по ссылке, значению или константе ссылки, скорее всего, потребует использования конструктора копирования или оператора присваивания. Что не нужно с указателями.

А а (новый В (1,2,3,4,5), новый С ('х', 'у', 'г'))

Обычно (т.е. не всегда) это плохая идея, потому что:

  1. Если A не освобождает аргументы, у вас есть утечка памяти.
  2. Если A принимает права собственности на аргументы и освобождает их, то вы не сможете передавать значения, выделенные в стек, в качестве аргументов.Тем не менее, в зависимости от вашего дизайна кода, это может быть приемлемым (Qt 4 часто требуется владение объектов, созданные с новой)

Где я должен освободить их?

Лучшая идея - убедиться, что компилятор автоматически освобождает аргументы. Это означает передачу по ссылке, константу или по значению. Или с помощью интеллектуальных указателей.

+0

Есть альтернативы передаче необработанного указателя. Например. 'Boost.Optional' для случая 3 и умный указатель типа' boost :: shared_ptr' для случая 4. Тогда вам не нужно иметь дело с ручным освобождением. – Philipp

+2

И я думаю, что важно сказать, что если конструктор генерирует исключение, у вас есть утечка памяти, потому что никто не освобождает B и C. Еще одна причина использовать интеллектуальные указатели :) –

+1

@Philipp: можете ли вы получить дополнительную ссылку? Я бы использовал 'shared_ptr' для случая 3 и' auto_ptr' для случая 4 (если только это не массив, и в этом случае применяются другие интеллектуальные указатели). –

1

Редактировать: Приведенные здесь примеры не соблюдают правило Большой тройки (спасибо @Philipp!). Если определение A используется, как указано ниже, код будет сбой при построении копирования для A или при назначении для A. Чтобы правильно определить код, оператор присваивания и конструктор копирования должны быть явно определены для A (или явно запрещены) объявленный как частный и никогда не реализованный). (Конец Edit)

Должен ли я передавать их по значению, по (сопзЬ) ссылки или указатель?

Если A использует В и С, а затем, удерживая их по ссылке или указателю внутри А. Для того, чтобы выбрать между ссылкой и указателем, увидеть, как B и C выделены.

Если они представляют собой локальные объекты стека, построенные в том же объеме, что и A, то передают их по ссылке const.

Если они динамически выделяются объекты, которые используют, сделать собственный их: пройти мимо них указателями и имеет деструктор A удалит их.

Если они необязательные компоненты А, передать их по указателю (который может быть пустым).

Если A не несет ответственности за удаление, отправьте их по следующему адресу: * const.

Где я могу их освободить?

Обычно, когда вы больше не нуждаетесь в них :).

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

Если они принадлежат A, удалите их в деструкторе для A. Это может иметь смысл также удалить их в течение жизни A, если указатели должны быть изменены.

Вот пример, где B является заменяемым компонентом, введенным в A (и принадлежащим A), а C является необязательным компонентом, принадлежащим A (но также введенным в A).

(«принадлежит» означает, что А отвечает за удаление обоих объектов)

class B; 
class C; 

class A 
{ 
    B* b; 
    C* c; 
public: 
    A(B* const bb, C* const cc = 0) // cc is optional 
    : b(bb), c(cc) 
    { 
    } 

    void resetB(B* const bb = 0) 
    { 
     delete b; 
     b = bb; 
    } 

    ~A() 
    { 
     resetB(); 
     delete c; 
    } 
}; 

{ 
    A a(new B, new C); 
    a.resetB(); // delete B 
    a.resetB(new B); // delete former B and set a new one 
} // both members of A are deleted 

Но я не знаю, является ли это хорошо практика или нет. Какие-либо предложения?

Это до вас на самом деле, но вы можете написать A a(B(1, 2, 4), C(1, 2, 3)) так легко, как A a(new B(1, 2, 4), new C(1,2,3)); (в первом случае - один без нового - А :: б и A :: с должны быть ссылки или объекты/значения внутри класс и A не должны удалять их вообще).

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

+1

Ваш пример не придерживается правила Большой тройки. Подумайте об использовании умного указателя вместо необработанного указателя. – Philipp

+0

@Philipp - Спасибо, я должен был указать это. Мой пример - не пример полного кода, просто как передать параметры. Я добавлю комментарий к моему ответу. – utnapistim

Смежные вопросы