Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.52/54: Рейтинг темы: голосов - 54, средняя оценка - 4.52
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705

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

05.11.2010, 21:40. Показов 12087. Ответов 53
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
...У меня в книге описаны случаи при которых вызывается конструктор копирования. Один из этих случаев:

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

Ну-с попробуем смоделировать такую ситуацию:
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 минуты
Спасибо заранее
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
05.11.2010, 21:40
Ответы с готовыми решениями:

Почему не вызывается конструктор копирования при возврате объекта из функции
Добрый день! Насколько мне известно, конструктор копирования вызывается: 1) при передачи объекта как аргумента функции ...

НЕ вызывается конструктор копирования
НЕ вызывается конструктор копирования (не явно), как сделать чтобы это было явно? #include &lt;iostream&gt; #include &lt;string&gt; ...

Когда вызывается конструктор копирования?
Пожалуйста помогите ответить на вопрос &quot;Когда вызывается конструктор копирования?&quot;

53
Делаю внезапно и красиво
Эксперт С++
 Аватар для Deviaphan
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
12.05.2011, 12:22
Студворк — интернет-сервис помощи студентам
Повторяю, в твоём коде нет смысла создавать временный объект. Вместо создания "arr obj" с последующим копированием в "arr x", сразу же создаётся "arr x". Т.е. не происходит побитового копирования, создаётся всего один объект и ничего копировать не нужно.
Я привёл тебе варианты, когда одним объектом обойтись нельзя и копирование будет происходить.
Почитай про оптимизации, которые делает твой компилятор, ты будешь оооочень удивлён. Я серьёзно. Он ведь и количество аргументов у функций менять может и порядок операций менять, много чего может. И всё это не сказывается на результате. Так же, как на результате не сказывается удаление промежуточного объекта.
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705
12.05.2011, 12:38  [ТС]
Цитата Сообщение от 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;
}
Вот, запусти и увидишь, что указатели указывают на один и тот же участок памяти. Уже удалённый, а нового нет, ибо МОЙ конструктор вызван не был.
И эта ситуация часта.
0
Делаю внезапно и красиво
Эксперт С++
 Аватар для Deviaphan
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
12.05.2011, 12:39
Функция вызовется, да. Но вывод в консоль никак не связан с объектов obj. Я это вижу, компилятор это видит. И он может его здесь не создавать и не копировать. У тебя слишком простой пример, который компилятор слишком хорошо оптимизирует.
Ты пойми, весь ненужный код оптимизатор по возможности убирает, а тут копирование излишне.
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705
12.05.2011, 12:41  [ТС]
Ну я там добавил, посмотри
...Да я уже понял, что копилятор не вызовет мой конструктор. Я благодарен ему и восхищаюсь его умению самому принимать решения.
...Но лучше бы он этого не делал, ибо результат- указывание указателя на несуществующую строку. А это посерьёзнее чем просто невывод диагностической надписи "вызван конструктор копирования". Это полная ж...а
0
Делаю внезапно и красиво
Эксперт С++
 Аватар для Deviaphan
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
12.05.2011, 12:42
Цитата Сообщение от kravam Посмотреть сообщение
указатели указывают на один и тот же участок памяти. Уже удалённый, а нового нет
Ибо ТВОЙ конструктор копирования не вызывался, т.к. использовался объект из строки 40. Т.е. он был создан ДО вызова функции get_object и, затем, в ней настраивался.
Я уже писал, отключи оптимизации.
0
Эксперт С++
2924 / 1274 / 114
Регистрация: 27.05.2008
Сообщений: 3,465
12.05.2011, 12:49
Цитата Сообщение от kravam Посмотреть сообщение
... а теперь вот другая ситуация; тоже должен вызываться конструктор копирования и тоже он не вызывается. Почему? Хотя в книге написано, что конструктор копирования вызывается, когда возвращаемое значение имеет тип класса!
В книге написано правильно. Теоретически, конструктор копирования должен быть вызван. Но разработчики компилятор - хииитрые! Они использовали положение Стандарта языка, разрешающее т.н. Return Value Optimization - RVO - т.е. создавать возвращаемый объект obj прямо в том месте, "куда" он возвращается. В этом случае - да, конструктор копирования не будет вызван, что экономит процессорное время и улучшает производительность программы. Возможно, автор книги либо не мог знать об RVO (если книга писалась в давние-давние времена....), либо пока сознательно не стал заострять на этом внимание.
2
Делаю внезапно и красиво
Эксперт С++
 Аватар для Deviaphan
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
12.05.2011, 12:58
Кроме того, оператор присваивания не обязан работать через конструктор копирования. И кроме момента создания объекта, он не будет заменён на конструктор копирования.

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

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

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

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

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

-felide-constructors

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

Получилось.
Ужасно.
.............................
Всем спасибо.
1
 Аватар для Kastaneda
5232 / 3205 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
12.05.2011, 18:12
Тоже заинтересовался этим делом, решил посмотреть дизасемблированный вид вот этого кода:
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 запрещено, поэтому:
Code
1
2
3
4
5
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);
}
результат:
Code
1
2
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 ===
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705
12.05.2011, 18:49  [ТС]
g++ -fno-elide-constructors

тогда по возврату из функции вызовется КК
(...Правда, я не знаю, какой у Вас компилятор.)
0
 Аватар для Kastaneda
5232 / 3205 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
12.05.2011, 18:54
Цитата Сообщение от kravam Посмотреть сообщение
g++ -fno-elide-constructors

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

Не по теме:

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

0
Эксперт С++
 Аватар для grizlik78
2382 / 1666 / 279
Регистрация: 29.05.2011
Сообщений: 3,402
27.06.2011, 00:51
Цитата Сообщение от kravam Посмотреть сообщение
Угу? Ну ты согласишься, что если эта функция вызовется, то
всё-таки obj создастся?
Здесь я соглашусь. Объект создастся.
Цитата Сообщение от kravam Посмотреть сообщение
И не будет скопирован (как я хочу посимвольно),
И здесь так. Не будет скопирован.
Цитата Сообщение от kravam Посмотреть сообщение
и будет уничтожен
и будет вызван его деструктор?
Уничтожен-то будет, вопрос когда. Вот по коду приведённому в цитируемом посте совершенно очевидно, что уничтожен этот единственный объект будет по завершении функции main, так как имя этому объекту x, а вовсе не obj. Именно потому, что не вызывался конструктор копирования. Не стоит считать создателей компилятора недотёпами.
Цитата Сообщение от kravam Посмотреть сообщение
Вот, запусти и увидишь, что указатели указывают на один и тот же участок памяти. Уже удалённый, а нового нет, ибо МОЙ конструктор вызван не был.
Никто его пока не удалял. Его потом удалят.
Придумать ситуацию, когда RVO принесёт вред наверное можно, но очень не просто.
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705
27.06.2011, 01:17  [ТС]
Не стоит повторять. Там было уже сказано, что в данном примере (слишком простом) копирование излишне и так далее. И вообще.
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705
21.08.2011, 22:35  [ТС]
...Возвращаясь к этой теме хочется отметить смешное поведение компилятора 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;
}
0
Freelance
Эксперт С++
 Аватар для asics
2891 / 1826 / 356
Регистрация: 09.09.2010
Сообщений: 3,841
21.08.2011, 22:44
Цитата Сообщение от kravam Посмотреть сообщение
//Вот эту херь надо то расскомментить, то закомментить, это КК и есть
//kl (kl const & o) {printf ("Вызов КК\n");}
Да ну...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
21.08.2011, 22:44
Помогаю со студенческими работами здесь

ООП Конструктор копирования вызывается сам
Столкнулся с такой проблемой. Еще до создания новых объектов Python - вызывается конструктор копирования. В чем дело? #define...

Сколько раз вызывается конструктор копирования
Почему n не увеличивается? Point(const Point&amp; src){ n++; set(src.x+1, src.y+1); cout &lt;&lt; &quot;Konstruction copyrovanija...

В каких случаях вызывается конструктор копирования, и стоит ли вообще об этом думать?
В книге Г. Шилдта написано, что конструктор копирования может неявно вызываться, при инициализации объекта значением, которое возращает...

Будет ли утрачена память, когда конструктор копирования вызывается для уже существующего объекта класса?
class A { char * v; A(); ~A(); A(const A &amp;obj); } ///////////////////// A::A() {

Почему не вызывается конструктор перемещения?
#include &lt;iostream&gt; #include &lt;vector&gt; class Object { public: Object() { std::cout &lt;&lt; &quot;Object()&quot; &lt;&lt; std::endl; ...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru