Форум программистов, компьютерный форум CyberForum.ru

Почему не вызывается конструктор копирования? - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 30, средняя оценка - 4.83
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,268
05.11.2010, 21:40     Почему не вызывается конструктор копирования? #1
...У меня в книге описаны случаи при которых вызывается конструктор копирования. Один из этих случаев:

: "Когда аргумент имеет тип класса. Создаётся копия аргумента и затем передаётся в функцию"

Ну-с попробуем смоделировать такую ситуацию:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
using namespace std;
 
class baze {
public:
 
 //Конструктр объекта класса baze, заданный по умолчанию
 baze () {printf ("wwwww\n");};
 
 //Эта функция, которая принимает ссыочный аргумент. Следовательно, при её вызове ДОЛЖЕН 
 //вызваться конструктр копирования
 void funktsia(const baze &other){
  printf ("lllll\n");
 }
 
 //А вот и сам конструктр копирования. Он иногда должен вызываться. Где- см. ниже 
 baze (const baze &src) {
  printf ("rrrrr\n");
 }
 
};
 
int main() {
 
 baze f;
 
 //В это месте должен вызываться конструктор копирования, ибо функция funktsia() принимает
 //ссылочный аргумент. Тычем на исполнение и ждём появления строчки "rrrrr"
 f.funktsia(f);
 
 //Но наблюдаем всего лишь "wwwww" (создался объект класса baze) и "lllll" (вызвана функция
 //funktsia () Как она приняла аргумент- для меня до сих пор загадка.)
 //Конструктор копирования не вызван. ПОчему?
 getchar ();
 return 0;
}
Добавлено через 2 минуты
Спасибо заранее
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.11.2010, 21:40     Почему не вызывается конструктор копирования?
Посмотрите здесь:

Сколько раз вызывается конструктор копирования C++
Будет ли утрачена память, когда конструктор копирования вызывается для уже существующего объекта класса? C++
Почему конструктор вызывается повторно при преобразовании типов? C++
Когда вызывается конструктор копирования? C++
Почему не вызывается конструктор копии? C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
12.05.2011, 12:22     Почему не вызывается конструктор копирования? #21
Повторяю, в твоём коде нет смысла создавать временный объект. Вместо создания "arr obj" с последующим копированием в "arr x", сразу же создаётся "arr x". Т.е. не происходит побитового копирования, создаётся всего один объект и ничего копировать не нужно.
Я привёл тебе варианты, когда одним объектом обойтись нельзя и копирование будет происходить.
Почитай про оптимизации, которые делает твой компилятор, ты будешь оооочень удивлён. Я серьёзно. Он ведь и количество аргументов у функций менять может и порядок операций менять, много чего может. И всё это не сказывается на результате. Так же, как на результате не сказывается удаление промежуточного объекта.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,268
12.05.2011, 12:38  [ТС]     Почему не вызывается конструктор копирования? #22
Цитата Сообщение от Deviaphan Посмотреть сообщение
Повторяю, в твоём коде нет смысла создавать временный объект. Вместо создания "arr obj" с последующим копированием в "arr x", сразу же создаётся "arr x".
Неправда, давай проверим, вот сюда добавим строчку:

C++
1
2
3
4
5
6
7
//А вот по возвращении из этой функции и должен будет ызваться МОЙ конструктор копирования
//Но он не вызовется  
arr get_object () {
 cout << "Вызов функции" << "\n";
 arr obj;
 return obj; 
}
Угу? Ну ты согласишься, что если эта функция вызовется, то
всё-таки obj создастся?
И не будет скопирован (как я хочу посимвольно),
и будет уничтожен
и будет вызван его деструктор?

Добавлено через 7 минут
В конце концов, чё это я, надо было сразу так написать:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <locale>
 
using namespace std;
class arr {
  public:
    arr(){p= new char [7]; strcpy (p, "stroka");};
    arr(const arr &obj);
    ~arr(){delete p;}
 
    char* get_p(){return p;}
 
  private:
    char* p;          
};
 
 
//Вот в этом конструкторе строка копируется посимвольно
arr::arr(const arr &obj){
 p= new char [7];
 strcpy (p, obj.p);
 cout << "Вызов копирующего конструктора" << "\n";
}
 
 
//А вот по возвращении из этой функции и должен будет ызваться МОЙ конструктор копирования
//Но он не вызовется  
arr get_object () {
 cout << "Вызов функции" << "\n";
 arr obj;
 printf ("obj.p =%x\n", obj.get_p());
 return obj; 
}
 
 
 
 
int main(){
 
  arr x= get_object();
  printf ("x.p =%x\n", x.get_p());
  //А теперь мы имеем, что x.p указывает на строку, которой нет, ибо
  //для указателя, котрый на неё указывал, была выполнена операция:
  //delete p (по выходе из функции get_object обюъект obj был разрушен и был вызван её деструктор)         
  
  getchar ();
  return 0;
}
Вот, запусти и увидишь, что указатели указывают на один и тот же участок памяти. Уже удалённый, а нового нет, ибо МОЙ конструктор вызван не был.
И эта ситуация часта.
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
12.05.2011, 12:39     Почему не вызывается конструктор копирования? #23
Функция вызовется, да. Но вывод в консоль никак не связан с объектов obj. Я это вижу, компилятор это видит. И он может его здесь не создавать и не копировать. У тебя слишком простой пример, который компилятор слишком хорошо оптимизирует.
Ты пойми, весь ненужный код оптимизатор по возможности убирает, а тут копирование излишне.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,268
12.05.2011, 12:41  [ТС]     Почему не вызывается конструктор копирования? #24
Ну я там добавил, посмотри
...Да я уже понял, что копилятор не вызовет мой конструктор. Я благодарен ему и восхищаюсь его умению самому принимать решения.
...Но лучше бы он этого не делал, ибо результат- указывание указателя на несуществующую строку. А это посерьёзнее чем просто невывод диагностической надписи "вызван конструктор копирования". Это полная ж...а
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
12.05.2011, 12:42     Почему не вызывается конструктор копирования? #25
Цитата Сообщение от kravam Посмотреть сообщение
указатели указывают на один и тот же участок памяти. Уже удалённый, а нового нет
Ибо ТВОЙ конструктор копирования не вызывался, т.к. использовался объект из строки 40. Т.е. он был создан ДО вызова функции get_object и, затем, в ней настраивался.
Я уже писал, отключи оптимизации.
CheshireCat
Эксперт С++
2907 / 1235 / 78
Регистрация: 27.05.2008
Сообщений: 3,307
12.05.2011, 12:49     Почему не вызывается конструктор копирования? #26
Цитата Сообщение от kravam Посмотреть сообщение
... а теперь вот другая ситуация; тоже должен вызываться конструктор копирования и тоже он не вызывается. Почему? Хотя в книге написано, что конструктор копирования вызывается, когда возвращаемое значение имеет тип класса!
В книге написано правильно. Теоретически, конструктор копирования должен быть вызван. Но разработчики компилятор - хииитрые! Они использовали положение Стандарта языка, разрешающее т.н. Return Value Optimization - RVO - т.е. создавать возвращаемый объект obj прямо в том месте, "куда" он возвращается. В этом случае - да, конструктор копирования не будет вызван, что экономит процессорное время и улучшает производительность программы. Возможно, автор книги либо не мог знать об RVO (если книга писалась в давние-давние времена....), либо пока сознательно не стал заострять на этом внимание.
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
12.05.2011, 12:58     Почему не вызывается конструктор копирования? #27
Кроме того, оператор присваивания не обязан работать через конструктор копирования. И кроме момента создания объекта, он не будет заменён на конструктор копирования.

Добавлено через 2 минуты
Кстати, в MSDN есть пример про удаление промежуточного объекта:
C++
1
2
3
4
5
6
A MyMethod (B &var)
{
   A retVal;
   retVal.member = var.value + bar(var);
   return retVal;
}
Ничего не напоминает? .)
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,268
12.05.2011, 13:36  [ТС]     Почему не вызывается конструктор копирования? #28
Цитата Сообщение от Deviaphan Посмотреть сообщение
Ибо ТВОЙ конструктор копирования не вызывался
Если это шутка, то неудачная, я битый час тебе об этом говорю уже.

Цитата Сообщение от Deviaphan Посмотреть сообщение
Я уже писал, отключи оптимизации.
как их отключать-то если они отключены? См. приложение
Вложения
Тип файла: rar optsii.rar (7.2 Кб, 10 просмотров)
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,268
12.05.2011, 13:39  [ТС]     Почему не вызывается конструктор копирования? #29
Цитата Сообщение от Deviaphan Посмотреть сообщение
Кроме того, оператор присваивания не обязан работать через конструктор копирования.
стоп, если ты про ЭТОТ вызов

C++
1
2
arr y;
arr x=y// ЭТО всё равно, что arr x(y)
Давай с ЭТИМ вызовом повременим, а то я запутаюсь вообще. Щас говорим о
C++
1
return x;
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
12.05.2011, 14:01     Почему не вызывается конструктор копирования? #30
http://msdn.microsoft.com/en-us/libr...=vs.80%29.aspx
Уж не знаю, как объяснить проще, чем там написано. Своими словами не удалось, попробую ихними.
Все претензии к Майкрософту, что они удаляют ненужный код.)

Добавлено через 1 минуту
Цитата Сообщение от kravam Посмотреть сообщение
я битый час тебе об этом говорю уже.
читай до конца
Цитата Сообщение от Deviaphan Посмотреть сообщение
Ибо ТВОЙ конструктор копирования не вызывался, т.к. использовался объект из строки 40. Т.е. он был создан ДО вызова функции get_object и, затем, в ней настраивался.
Добавлено через 1 минуту
Значит, этот код настолько очевиден для компилятора, что он даже при выключенных оптимизациях от него избавляется.) Запусти под дебагом, там точно всё будет, как тебе хочется.
fasked
Эксперт C++
 Аватар для fasked
4924 / 2504 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
12.05.2011, 14:08     Почему не вызывается конструктор копирования? #31
kravam, если одни объекты имеют одинаковое состояние (они полные копии друг друга) и не изменяются на протяжении какого-то участка времени, то компилятор вполне может использовать для разных казалось бы объектов одну область памяти. Чтобы они были по настоящему разными - надо их изменять и тогда компилятор будет вынужден создавать копии.

Тоже самое касательно создания/несоздания объектов. Если объект никак не используется, то компилятор может его вообще не создавать. Чтобы обязать компилятор выполнять вообще все описанные программистом действия, то надо помечать переменную как volatile.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,268
12.05.2011, 14:09  [ТС]     Почему не вызывается конструктор копирования? #32
А как под дебагом запускать?
А вообще вот, я нашёл:
(GCC._Полное_руководство_(Гриффитс))

-felide-constructors

Действует по умолчанию. Упрощает rенерируемый код, если он вызывает функ
цию, возвращающую объект значением ero адреса. В результате оптимизации фун
кция создает экземпляр объекта непосредственно в указанном расположении воз
вращаемоrо значения вместо использования конструктора копирования объекта,
созданноrо внутри локальной области действия функции. Это может вызывать
проблемы в случае, если конструктор оказывает побочное действие на результат.
Отменить значение флаrа по умолчанию можно применением обратной опции
-fno-elide-constructors

Получилось.
Ужасно.
.............................
Всем спасибо.
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4236 / 2769 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
12.05.2011, 18:12     Почему не вызывается конструктор копирования? #33
Тоже заинтересовался этим делом, решил посмотреть дизасемблированный вид вот этого кода:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
 
using namespace std;
 
class arr
{
public:
    arr(int number) {};
    arr(const arr &obj);
};
 
 
arr::arr(const arr &obj)
{
    cout << "Вызов копирующего конструктора" << "\n";
}
 
 
arr get_object (int number)
{
    arr obj (number);
    return obj;
}
 
 
 
 
int main()
{
    arr x=get_object(15);
    return 0;
}
Вобщем там в ф-ции get_object() вызывается конструктор с адресом (а в конструктор первым аргументом незаметно передается адрес (this)) объекта x из функции main(). Причем, наплевав на соглашение cdecl, параметры передаются в регистрах (тоже оптимизация). Странно, что при таком подходе компилятор вызов ф-ции оставил, мог бы тоже убрать

Добавлено через 41 минуту
Цитата Сообщение от fasked Посмотреть сообщение
то надо помечать переменную как volatile
Конструктор копирования принимает в качестве аргумента const Type&, а автоматическое привидение volatile к const запрещено, поэтому:
Код
main.cpp In function 'arr get_object(int)':
main.cpp|23|error: no matching function for call to 'arr::arr(volatile arr&)'
main.cpp|13|note: candidates are: arr::arr(const arr&)
main.cpp|8|note:                 arr::arr(int)
=== Build finished: 1 errors, 0 warnings ===|
вобщем я так и не смог своими силами заставить компилятор вызвать конструктор копирования...

Добавлено через 2 минуты
пробовал так:
C++
1
2
3
4
5
arr get_object (int number)
{
   volatile arr obj (number);
    return const_cast<const arr>(obj);
}
результат:
Код
main.cpp|23|error: invalid use of const_cast with type 'const arr', which is not a pointer, reference, nor a pointer-to-data-member type
=== Build finished: 1 errors, 0 warnings ===
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,268
12.05.2011, 18:49  [ТС]     Почему не вызывается конструктор копирования? #34
g++ -fno-elide-constructors

тогда по возврату из функции вызовется КК
(...Правда, я не знаю, какой у Вас компилятор.)
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4236 / 2769 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
12.05.2011, 18:54     Почему не вызывается конструктор копирования? #35
Цитата Сообщение от kravam Посмотреть сообщение
g++ -fno-elide-constructors

тогда по возврату из функции вызовется КК
(...Правда, я не знаю, какой у Вас компилятор.)
MinGW. Но дело не в этом, я хотел заставить компилятор вызвать КК без ключей компиляции, "силой магии" так сказать...
kravam
12.05.2011, 18:57  [ТС]
  #36

Не по теме:

Знакомый порыв...

grizlik78
Эксперт C++
 Аватар для grizlik78
1882 / 1414 / 101
Регистрация: 29.05.2011
Сообщений: 2,958
27.06.2011, 00:51     Почему не вызывается конструктор копирования? #37
Цитата Сообщение от kravam Посмотреть сообщение
Угу? Ну ты согласишься, что если эта функция вызовется, то
всё-таки obj создастся?
Здесь я соглашусь. Объект создастся.
Цитата Сообщение от kravam Посмотреть сообщение
И не будет скопирован (как я хочу посимвольно),
И здесь так. Не будет скопирован.
Цитата Сообщение от kravam Посмотреть сообщение
и будет уничтожен
и будет вызван его деструктор?
Уничтожен-то будет, вопрос когда. Вот по коду приведённому в цитируемом посте совершенно очевидно, что уничтожен этот единственный объект будет по завершении функции main, так как имя этому объекту x, а вовсе не obj. Именно потому, что не вызывался конструктор копирования. Не стоит считать создателей компилятора недотёпами.
Цитата Сообщение от kravam Посмотреть сообщение
Вот, запусти и увидишь, что указатели указывают на один и тот же участок памяти. Уже удалённый, а нового нет, ибо МОЙ конструктор вызван не был.
Никто его пока не удалял. Его потом удалят.
Придумать ситуацию, когда RVO принесёт вред наверное можно, но очень не просто.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,268
27.06.2011, 01:17  [ТС]     Почему не вызывается конструктор копирования? #38
Не стоит повторять. Там было уже сказано, что в данном примере (слишком простом) копирование излишне и так далее. И вообще.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,268
21.08.2011, 22:35  [ТС]     Почему не вызывается конструктор копирования? #39
...Возвращаясь к этой теме хочется отметить смешное поведение компилятора g++
Итак, мы договорились, что компилятор умный и не вызывает КК без надобности.
...Итак, все опции по умолчанию. Пишем свой КК- он не вызывается (это обсуждено). Но вот когда мы его убираем, встроенный КК вызывается (А знаю я это откуда? А по адресам смотрю...)! То есть ситуация та же самая- просто тупо скопировать побайтно объект не содержащий никаких указателей ни никакие строки но КК вызывается.
Кроме смеха из этого можно извлечь урок:

если хочешь, чтобы КК не вызывался- НАПИШИ ЕГО.
если хочешь, чтобы КК вызывался- НЕ ПИШИ ЕГО

Именно так, я ничё не придумал. Компилим и смотрим на адреса. А потом расскоментиваем эту строчку
C++
1
kl (kl const & o) {printf ("Вызов КК\n");}
ещё раз компилим и снова смотрим на адреса. Безо всяких опций то есть меняем поведение компилятора на желаемое. Цирк да и только.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <windows.h>
#include <iostream>
class kl {
 
 private:
         int x;
 
 public:
 //Конструкторы
 kl () {};
 
 
 //Вот эту херь надо то расскомментить, то закомментить, это КК и есть
 //kl (kl const & o) {printf ("Вызов КК\n");}
 
 friend void v (const kl &obekt) {
  printf ("адреса ссылочного аргумента равны %x\n", &obekt);
 } 
 
 kl func ();
};
 
kl kl::func () {
 kl obekt;
 printf ("адреса аргумента типа ima_klassa равны %x\n", &obekt);
 return obekt; 
}
 
int main() {
 SetConsoleCP(1251);
 SetConsoleOutputCP(1251);
 kl obekt;
 v (obekt.func());
 getchar ();
 return 0;
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.08.2011, 22:44     Почему не вызывается конструктор копирования?
Еще ссылки по теме:

C++ В каких случаях вызывается конструктор копирования, и стоит ли вообще об этом думать?
Почему конструктор вызывается при присвоении объекта другому объекту C++
C++ Почему не вызывается конструктор копирования при возврате объекта из функции

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
asics
Freelance
Эксперт C++
 Аватар для asics
2838 / 1775 / 144
Регистрация: 09.09.2010
Сообщений: 3,842
21.08.2011, 22:44     Почему не вызывается конструктор копирования? #40
Цитата Сообщение от kravam Посмотреть сообщение
//Вот эту херь надо то расскомментить, то закомментить, это КК и есть
//kl (kl const & o) {printf ("Вызов КК\n");}
Да ну...
Yandex
Объявления
21.08.2011, 22:44     Почему не вызывается конструктор копирования?
Ответ Создать тему
Опции темы

Текущее время: 21:00. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru