Создание экземпляра класса
Какая разница между строками 1, 2, 3, 4?
Когда я использую каждый?
Почему строка 3 печатает constructor Foo
, а строка 7 возвращает ошибку, а строка 8 не работает?
#include <iostream>
using namespace std;
class Foo
{
public:
Foo ( )
{
cout << "constructor Foo\n";
}
};
class Bar
{
public:
Bar ( Foo )
{
cout << "constructor Bar\n";
}
};
int main()
{
/* 1 */ Foo* foo1 = new Foo ();
/* 2 */ Foo* foo2 = new Foo;
/* 3 */ Foo foo3;
/* 4 */ Foo foo4 = Foo::Foo();
/* 5 */ Bar* bar1 = new Bar ( *new Foo() );
/* 6 */ Bar* bar2 = new Bar ( *new Foo );
/* 7 */ Bar* bar3 = new Bar ( Foo foo5 );
/* 8 */ Bar* bar3 = new Bar ( Foo::Foo() );
return 1;
}
Ответы
Ответ 1
/* 1 */ Foo* foo1 = new Foo ();
Создает объект типа Foo
в динамической памяти. foo1
указывает на это. Как правило, вы не будете использовать raw-указатели в С++, а скорее умный указатель. Если Foo
был POD-типом, это выполнило бы инициализацию значения (оно здесь не применяется).
/* 2 */ Foo* foo2 = new Foo;
Идентичен ранее, поскольку Foo
не является типом POD.
/* 3 */ Foo foo3;
Создает объект Foo
с именем foo3
в автоматическом хранилище.
/* 4 */ Foo foo4 = Foo::Foo();
Использует копию-инициализацию для создания объекта Foo
с именем foo4
в автоматическом хранилище.
/* 5 */ Bar* bar1 = new Bar ( *new Foo() );
Использует конструктор преобразования Bar
для создания объекта типа Bar
в динамическом хранилище. bar1
является указателем на него.
/* 6 */ Bar* bar2 = new Bar ( *new Foo );
То же, что и раньше.
/* 7 */ Bar* bar3 = new Bar ( Foo foo5 );
Это просто недопустимый синтаксис. Вы не можете объявить там переменную.
/* 8 */ Bar* bar3 = new Bar ( Foo::Foo() );
Будет работать и работать по тому же принципу с 5 и 6, если bar3
не был объявлен в 7.
5 и 6 содержат утечки памяти.
Синтаксис вроде new Bar ( Foo::Foo() );
не является обычным. Обычно это new Bar ( (Foo()) );
- дополнительная скобка для наиболее неприятного анализа. (исправлено)
Ответ 2
- Выделяет некоторую динамическую память из свободного хранилища и создает объект в этой памяти, используя свой конструктор по умолчанию. Вы никогда не удаляете его, поэтому происходит утечка памяти.
- Точно так же, как 1; в случае пользовательских типов скобки необязательны.
- Выделяет некоторую автоматическую память и создает объект в этой памяти с использованием своего конструктора по умолчанию. Память освобождается автоматически, когда объект выходит из области видимости.
- Аналогично 3. По идее, именованный объект
foo4
инициализируется построением по умолчанию, копированием и уничтожением временного объекта; обычно это устраняется, давая тот же результат, что и 3.
- Выделяет динамический объект, затем инициализирует вторую, копируя первый. Оба объекта просочились; и нет способа удалить первый, так как вы не указали на него указатель.
- Точно так же, как 5.
- Не компилируется.
Foo foo5
- это объявление, а не выражение; аргументы функции (и конструктора) должны быть выражениями.
- Создает временный объект и инициализирует динамический объект, копируя его. Протекает только динамический объект; временное уничтожается автоматически в конце полного выражения. Обратите внимание, что вы можете создать временное значение только с
Foo()
, а не с эквивалентом Foo::Foo()
(или действительно Foo::Foo::Foo::Foo::Foo()
)
Когда я использую каждый?
- Не делайте, если вам не нравятся ненужные украшения вашего кода.
- Если вы хотите создать объект, который выделяет текущую область. Не забудьте удалить его, когда вы закончите с ним, и научитесь использовать интеллектуальные указатели для более эффективного управления жизнью.
- Если вам нужен объект, который существует только в текущей области.
- Не думайте, если вы думаете, что 3 выглядит скучно и что добавить ненужное украшение.
- Не делайте этого, потому что он утечки памяти без шансов на восстановление.
- Не делайте этого, потому что он утечки памяти без шансов на восстановление.
- Не нужно, потому что он не будет компилироваться
- Если вы хотите создать динамический
Bar
из временного Foo
.
Ответ 3
Строки 1,2,3,4 вызовут конструктор по умолчанию. Они по сути различны, поскольку 1,2 - динамически созданный объект, а 3,4 - статически созданные объекты.
В строке 7 вы создаете объект внутри вызова аргумента. Таким образом, это ошибка.
И строки 5 и 6 являются приглашением на утечку памяти.