C ++ Проблема инициализации объекта дважды - PullRequest
2 голосов
/ 04 мая 2009

Я относительно новичок в C ++, и мне трудно понять, как создаются объекты и указатели на объекты.

В чем разница между этими двумя объявлениями с точки зрения памяти и использования? :

MyClass obj1;
MyClass *obj2;

И еще одна проблема, с которой я столкнулся, заключается в том, что у меня есть класс с коротким массивом без знака, в котором изменяется последнее пространство массива, если я делаю это:

MyClass obj;
obj = MyClass("123");

MyClass имеет два конструктора, один из которых будет принимать целое число и по умолчанию присваивает ему ноль и объединяет его в части по 3 цифры или менее. И другой, который будет принимать строковое представление числа и делать то же самое ... надеюсь, что это имеет смысл!

Хорошо работает, если я это объявлю

MyClass obj = MyClass("123123123");

но нет, если я сделаю это по-другому. Почему?

Ответы [ 6 ]

8 голосов
/ 04 мая 2009

разница:

MyClass  obj1;
MyClass *obj2;

Здесь obj1 является экземпляром MyClass.
В то время как obj2 потенциально может содержать адрес экземпляра MyClass.

Также obj1 будет автоматически инициализироваться конструкторами, в то время как obj2 не инициализируется по умолчанию (и, следовательно, указывает на случайную память). После инициализации obj2 может принимать специальное значение NULL, которое указывает, что оно не указывает на объект.

obj2 = &obj1;

Здесь мы инициализируем obj2, чтобы он указывал на адрес в памяти obj1. Если вы измените какой-либо из членов obj1, вы сможете увидеть изменения, посмотрев на них через obj2 (но поскольку obj2 является указателем, вам нужно отменить ссылку).

obj1.plop = 5;

std::cout << obj1.plop << "\n";
std::cout << obj2->plop << "\n";  Should print the same values. 

На самом деле следующие две вещи:

MyClass obj;
obj = MyClass("123");
  • Первая строка инициализирует 'obj' конструктором по умолчанию.
  • Вторая строка: создает временный объект, построенный со строкой «123». Как только этот временный объект создан, он копируется в 'obj' с помощью оператора присваивания. Если вы не определили оператор присваивания, компилятор сгенерирует его для вас. Если ваш класс содержит указатели, то версия по умолчанию, вероятно, не будет работать правильно (в большинстве других ситуаций оператор присваивания по умолчанию должен работать нормально).

Эта строка, вероятно, работает:

MyClass obj = MyClass("123123123");

Поскольку компилятор оптимизировал это в:

MyClass obj("123123123");
3 голосов
/ 04 мая 2009

Когда вы говорите MyClass obj1;, вы создаете объект. MyClass * obj2; просто экономит место для адреса объекта.

Итак MyClass obj1; делает следующее:

  • устанавливает имя в таблице символов компилятора
  • выделяет sizeof(MyClass) байтов пространства - может быть настолько большим, насколько вы хотите
  • он запускает ctor по умолчанию MyClass, MyClass :: MyClass () 9 или ctor, который имеет все аргументы по умолчанию intead), помещая инициализированный объект в пространство, которое он выделил
  • он запоминает, где находится этот объект, связывая его с именем 'obj1' в таблице символов.

, а MyClass * obj2; вместо

  • устанавливает имя obj2 в таблице символов
  • выделяет место только для адреса объекта MyClass, sizeof(MyClass*) - возможно, 4 или 8 байтов
  • не запускает конструктор.

Когда вы говорите MyClass obj; obj = MyClass("123123123") вы

  • создание и выделение MyClass объекта для obj с использованием ctor по умолчанию
  • создать и выделить другой MyClass объект
  • назначить этот новый MyClass объект для замены старого.
2 голосов
/ 04 мая 2009

при звонке

MyClass obj = MyClass("123123123");

Вы на самом деле создаете два объекта! Правильный способ - позвонить

MyClass obj("123123123");
0 голосов
/ 05 мая 2009

Эти объявления влияют на две вещи: время жизни переменной и место, где выделяется память.

Версия указателя MyClass * объявляет переменную, которая указывает на экземпляр MyClass. Он сам не выделяет его; выделение из «свободного хранилища» (которое всегда совпадает с «кучей») происходит при явном «новом» его освобождении и освобождается при его «удалении».

Работает следующий код:

MyClass* test_works() {
  MyClass* obj = new MyClass;
  return obj;
}

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

Сбой следующего кода, например:

MyClass* test_crashes() {
  MyClass obj;
  return &obj;
}
0 голосов
/ 04 мая 2009

разница между

MyClass obj1;
MyClass *obj2;

Если первый создает объект (размер = размер объекта), тогда как второй создает только указатель на объект (4 байта в 32-разрядных системах), но не фактический объект. Для этого вам нужно сделать

MyClass* obj2 = new MyClass("123");

Это выделит 4 байта для указателя, а x байтов, где x - размер объекта. Если вы вручную «создали» что-то подобное, то вы несете ответственность за ручное уничтожение этого позже, используя «delete».

MyClass obj1 будет «уничтожен», когда выйдет за рамки.

0 голосов
/ 04 мая 2009

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

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

В третьем фрагменте кода, который вы предоставили, вы фактически используете один конструктор, который принимает параметр. Не присваивание происходит.

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