Russian Qt Forum

Программирование => С/C++ => Тема начата: blood_shadow от Январь 08, 2011, 21:41



Название: параметр конструктора
Отправлено: blood_shadow от Январь 08, 2011, 21:41
Всем добрый вечер,

Почему работает данный код:
Код:
class Cell : QTableWidgetItem
{

public:
    Cell();
    QTableWidgetItem* clone() const;

};

Cell::Cell()
{
    cout << "In Cell Constr" << endl;
}

QTableWidgetItem* Cell::clone() const
{
    return new Cell(*this);
}

а именно почему мы можем передать конструктору параметр *this в передпоследней строке если у него нет параметров?


Название: Re: параметр конструктора
Отправлено: alexman от Январь 08, 2011, 21:43
Так конструктор копирования всегда есть по умолчанию.


Название: Re: параметр конструктора
Отправлено: Fat-Zer от Январь 08, 2011, 21:48
Если хотите запретить надо сделать его закрытым...


Название: Re: параметр конструктора
Отправлено: blood_shadow от Январь 08, 2011, 22:05
Так конструктор копирования всегда есть по умолчанию.
а понял, все время забываю о конструкторе копирования  :)
этот фрагмент я выдрал с книги Саммерфильда и Бланшета, тогда еще такой вопрос
зачем копировать если можно допустим просто создавать объект или эт будет быстрее?


Название: Re: параметр конструктора
Отправлено: alexman от Январь 08, 2011, 22:09
Вопрос непонятен. Лучше почитай где используется конструктор копирования.


Название: Re: параметр конструктора
Отправлено: blood_shadow от Январь 08, 2011, 23:11
Вопрос непонятен. Лучше почитай где используется конструктор копирования.
все разобрался...
остался вопрос по поводу записи:
Код:
return new Cell(*this);
тут вызывается конструктор копирования который делает побитовую копию, которую оператор new размещает в куче, а ретурн просто возращает указатель на этот объект в куче.
Я правильно мыслю?


Название: Re: параметр конструктора
Отправлено: Fat-Zer от Январь 08, 2011, 23:17
да... только не "побитовою"


Название: Re: параметр конструктора
Отправлено: blood_shadow от Январь 08, 2011, 23:27
да... только не "побитовою"
а какой? вроде же конструктор копирование делает побитовую копию, это я прочитал в книге Шилдта, там написано:
"По  умолчанию, если один объект инициализируется другим, создается побитовая копия присваиваемого объекта"
значит если это верно то и в куче должна появиться побитовая копия объекта


Название: Re: параметр конструктора
Отправлено: alexman от Январь 09, 2011, 00:23
да... только не "побитовою"
а какой? вроде же конструктор копирование делает побитовую копию, это я прочитал в книге Шилдта, там написано:
"По  умолчанию, если один объект инициализируется другим, создается побитовая копия присваиваемого объекта"
значит если это верно то и в куче должна появиться побитовая копия объекта
Все правильно!


Название: Re: параметр конструктора
Отправлено: Fat-Zer от Январь 09, 2011, 00:25
имел в виду, что реально не копируется каждый бит по отдельности... в лучшем случае побайтовую, а скорей всего всё будет делаться одной/двумя инструкциями. просто правильнее было бы сказать точную копию. не перите в голову. просто не понравилось слово ;)

да, brankovic прав. моя ошибка.


Название: Re: параметр конструктора
Отправлено: brankovic от Январь 09, 2011, 01:33
"По  умолчанию, если один объект инициализируется другим, создается побитовая копия присваиваемого объекта"

Это полная ерунда. На самом деле:

struct X
{
   int i;
   char ch;
   std::string s;
};

конструктор копирования X вызовет конструктор копирования для каждого элемента. Для i и ch это, конечно, побитовая копия, но для s это вызов конструктора std::string, с маллоками, копированием байт и т.д.


Название: Re: параметр конструктора
Отправлено: juvf от Январь 09, 2011, 08:38
"Философия С++. Введение в стандарт", Брюс Эккель, глава 11, стр. 344
Цитировать
Чтобы создать копирующий конструктор для класса, использующего композицию (а также наследование - глава 14), компилятор рекурсивно вызывает копирующие конструкторы всех объектов класса и базовых классов.
Там же, в этой главе, примеры, доказывающие это. В вашем случае blood_shadow , с классом Cell, вывозится коп. конст. для QTableWidgetItem. Смотрим асистент
Цитировать
QTableWidgetItem::QTableWidgetItem ( const QTableWidgetItem & other )
Constructs a copy of other. Note that type() and tableWidget() are not copied.
Попробуйте проверить. Создайте класс Cell, задайте type и tableWidget. создайте копию и посмотрите у копии type и tableWidget. Если у Cell был поразрядный конструктор, то type и tableWidget должны сохранится.


Название: Re: параметр конструктора
Отправлено: Igors от Январь 09, 2011, 09:11
имел в виду, что реально не копируется каждый бит по отдельности... в лучшем случае побайтовую, а скорей всего всё будет делаться одной/двумя инструкциями. просто правильнее было бы сказать точную копию. не перите в голову. просто не понравилось слово ;)
Никакого "копирования памяти" не происходит. Default конструктор копирования вызывает конструкторы копирования для всех членов. В ассемблере это обычно большой кусок кода. "Точная копия" гарантируется только для POD структур.

Кароче читайте книжки и учите С++  ;)
 :)

Edit: пардон, просмотрел: brankovic уже ответил


Название: Re: параметр конструктора
Отправлено: blood_shadow от Январь 09, 2011, 12:35
Цитировать
Попробуйте проверить. Создайте класс Cell, задайте type и tableWidget. создайте копию и посмотрите у копии type и tableWidget. Если у Cell был поразрядный конструктор, то type и tableWidget должны сохранится.
это не из-за того, тут и так понятно что ф-ции не копируются более того ф-ции существуют еще до создания любых объектов, вот здесь более-менее норм описаны процессы - http://www.devdoc.ru/index.php/content/view/virtual_base.htm
думаю автор книги имел ввиду правило про данные, хотя как оказалось с постов выше это и для данных-объектов неверно


Название: Re: параметр конструктора
Отправлено: blood_shadow от Январь 09, 2011, 12:56
конструктор копирования X вызовет конструктор копирования для каждого элемента. Для i и ch это, конечно, побитовая копия, но для s это вызов конструктора std::string, с маллоками, копированием байт и т.д.

в этой записи:
Код:
return new Cell(*this);

тут сразу новый(скопированный объект конструктором копирования) появляется в куче? или еще раз копируются в кучу потом после создания копии?


Название: Re: параметр конструктора
Отправлено: Igors от Январь 09, 2011, 16:59
в этой записи:
Код:
return new Cell(*this);
тут сразу новый(скопированный объект конструктором копирования) появляется в куче? или еще раз копируются в кучу потом после создания копии?
"Сразу" ничего появиться не может. Выделяется память в куче под объект и вызывается конструктор копирования который
   - сначала выполняет спец. действия для распределенного объекта (напр прописывает указатель на VMT)
   - вызывает конструкторы копирования для каждого члена объекта


Название: Re: параметр конструктора
Отправлено: blood_shadow от Январь 09, 2011, 18:22
Цитировать
"Сразу" ничего появиться не может. Выделяется память в куче под объект и вызывается конструктор копирования который
извиняюсь за дотошность -
а как насчет приоритета операций? то есть я имею ввиду что следуя приоритету операция сначала должен вызваться конструктор копирования Cell(*this)
и только потом вызов оператора new или приоритет операции "()" не имеет отношения к созданию/копированию объекта?   


Название: Re: параметр конструктора
Отправлено: Igors от Январь 09, 2011, 18:31
извиняюсь за дотошность -
а как насчет приоритета операций? то есть я имею ввиду что следуя приоритету операция сначала должен вызваться конструктор копирования Cell(*this)
и только потом вызов оператора new или приоритет операции "()" не имеет отношения к созданию/копированию объекта?   
Не имеет. Сначала распределяется память, затем зовется конструктор (копирования или какой указали)


Название: Re: параметр конструктора
Отправлено: lit-uriy от Январь 09, 2011, 18:44
>>и только потом вызов оператора new или приоритет операции "()"
здесь нет операции скобки, это форма записи любой функции:
funcname()
, а в данном случае конструктора


Название: Re: параметр конструктора
Отправлено: blood_shadow от Январь 09, 2011, 18:59
здесь нет операции скобки, это форма записи любой функции:
funcname()
, а в данном случае конструктора
вроде ж как конструктор - это не ф-ция и я так предполагаю что конструктор копирования тоже нет.
а если посмотреть по приоритету операторов то вот этот оператор вызова ф-ции "()" стоит почти в самом верху выше new,
осмелюсь предположить что если new вызывается первым то и конструктор не является ф-цией и создание/копирование объекта
носит немного другой характер нежели просто оператор вызова ф-ции
Если неправ, поправьте пожалуйста


Название: Re: параметр конструктора
Отправлено: Igors от Январь 09, 2011, 20:50
осмелюсь предположить что если new вызывается первым то и конструктор не является ф-цией и создание/копирование объекта
носит немного другой характер нежели просто оператор вызова ф-ции
Если неправ, поправьте пожалуйста
Конечно прав, ф-цию в new никак не воткнуть. А лучше/проще в отладчике посмотреть чем листать книги  :) По ходу дела: с new можно и не выделять память в куче, а указать адрес. Это ценная возможность


Название: Re: параметр конструктора
Отправлено: blood_shadow от Январь 09, 2011, 23:09
Конечно прав, ф-цию в new никак не воткнуть. А лучше/проще в отладчике посмотреть чем листать книги  :) По ходу дела: с new можно и не выделять память в куче, а указать адрес. Это ценная возможность
извиняюсь за скудость своих познаний, но буду очень вам благодарен если скажете как в отладчике посмотреть что первое вызывается, использую креатор с gdb отладчиком, поставил точку останова на строке
Код:
 return new Cell(*this); 
но он выдает только адреса ф-ций Cell::clone() и main и также указатель this на что ссылается и больше ничего, если пошагово потом исполнять дает только адрес указателя которому присваивается возврат указателя
Спасибо  :)


Название: Re: параметр конструктора
Отправлено: brankovic от Январь 10, 2011, 00:39
поставил точку останова на строке
Код:
 return new Cell(*this); 

Создайте явно конструктор копирования Cell (Cell const &) и в нём поставьте брейк. Увидите по стеку, что вы внутри оператора new. Но вы всё равно кода new не увидите, его генерит gcc сразу в ассемблер.

Не заморачивайтесь про приоритет операций, это одна операция "new Cell (*this)", просто синтаксис new в C++ весьма морочный. Новички с других языков часто отождествляют new и конструктор объекта -- это совершенно разные вещи! Для пущей путаницы операторов new несколько:
1. обычный new
2. placement new
3. ещё целый зоопарк, но нам они не важны

Вы используете обычный new:

return new Cell (*this); //аргументы могут быть любые, главное чтобы существовал такой конструктор

Он (упрощенно) эквивалентен вызову функции:

Код
C++ (Qt)
Cell *operator_new (Cell const &c)
{
  Cell *ptr = (Cell*) malloc (sizeof (Cell));
  if (ptr == 0)
     throw std::bad_alloc ();
  new (ptr) Cell (c); //***PLACEMENT NEW***
  return ptr;
}
 

обратите внимание на конструкцию:

new (ptr) Cell (c);

это и есть placement new. По смыслу это

ptr->Cell::Cell (c);

, т.е. вызов конструктора копирования с this равным ptr, но просто вызвать конструктор как я написал нельзя -- компилятор ругнётся. Зачем так сделано я не знаю, но так обстоят дела. Этот placement new используется для написания контейнеров, но в обычной жизни можно без него обойтись.

P.S.: конструктор это именно функция, такая же как и остальные, просто с некоторыми отклонениями в части синтаксиса. А в записи "new Class (a, b, c)" никакого вызова функции нет, это вызов оператора new.


Название: Re: параметр конструктора
Отправлено: blood_shadow от Январь 10, 2011, 01:18

Создайте явно конструктор копирования Cell (Cell const &) и в нём поставьте брейк. Увидите по стеку, что вы внутри оператора new. Но вы всё равно кода new не увидите, его генерит gcc сразу в ассемблер.


Не знаю что даже сказать, конструктор копирования создан, точка поставлена, вот что получилось:
(http://img209.imageshack.us/img209/56/debug.jpg)
как-то оно бедно и помоему ничего не очевидно


Название: Re: параметр конструктора
Отправлено: blood_shadow от Январь 10, 2011, 01:39


Код
C++ (Qt)
Cell *operator_new (Cell const &c)
{
  Cell *ptr = (Cell*) malloc (sizeof (Cell));
  if (ptr == 0)
     throw std::bad_alloc ();
  new (ptr) Cell (c); //***PLACEMENT NEW***
  return ptr;
}
 

в этом коде с объявлением оператора так как выше
Код:
 return new Cell (*this); 
вызов new будет выглядеть вот так: operator_new(Cell (*this)) или он будет вызываться как-то по другому не так как ф-ция?


Название: Re: параметр конструктора
Отправлено: juvf от Январь 10, 2011, 06:34
to blood_shadow
Цитировать
это не из-за того, тут и так понятно что ф-ции не копируются более того ф-ции существуют еще до создания любых объектов
да я вроде про функции не говорил. Может смутила запись из асистанта "Note that type() and tableWidget() are not copied." Ну я её понимаю не буквально, я понимаю что параметр type (его тип int), который получил конструктор, не скопируется. Также table widget that contains the item (тип QTableWidget *) не скопируется.

Цитировать
но буду очень вам благодарен если скажете как в отладчике посмотреть что первое вызывается
ну так глобально переопределить оператор new и переопределить копирующий конструктор Cell. До кучи переопределить копирующий конструктор QTableWidgetItem. Чтоб с gdb не заморачиваться, можно в переопределённых конструкторах и в переопределённом new выводить что-нибудь в cout. Последовательность сообщений в кансоле и будет последовательностью вызова функций.


Название: Re: параметр конструктора
Отправлено: brankovic от Январь 10, 2011, 13:17
вызов new будет выглядеть вот так: operator_new(Cell (*this)) или он будет вызываться как-то по другому не так как ф-ция?

operator_new (*this);

Но есть нюанс. Форма operator_new (Cell (*this)) тоже отработает, потому что распадается на 2 операции:

Cell tmp (*this);
operator_new (tmp);

Так же отработает operator_new (Cell (Cell (Cell (*this)))), такой вызов аналогичен:

Cell const a1 (*this);
Cell const a2 (a1);
Cell const a3 (a2);
operator_new (a3);

Только последний из объектов будет создан в куче, a1, a2 и a3 будут созданы на стеке безо всякого new.