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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 30, средняя оценка - 4.83
kravam
быдлокодер
1700 / 887 / 45
Регистрация: 04.06.2008
Сообщений: 5,493
#1

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

05.11.2010, 21:40. Просмотров 3996. Ответов 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
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.11.2010, 21:40
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Почему не вызывается конструктор копирования? (C++):

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

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

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

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

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

Почему не вызывается конструктор копии? - C++
Почему не вызывается конструктор копии? class CPoint { friend std::istream &amp;operator&gt;&gt;(std::istream &amp;in, CPoint &amp;obj); friend...

53
fasked
Эксперт С++
4945 / 2525 / 180
Регистрация: 07.10.2009
Сообщений: 4,311
Записей в блоге: 1
12.05.2011, 14:08 #31
kravam, если одни объекты имеют одинаковое состояние (они полные копии друг друга) и не изменяются на протяжении какого-то участка времени, то компилятор вполне может использовать для разных казалось бы объектов одну область памяти. Чтобы они были по настоящему разными - надо их изменять и тогда компилятор будет вынужден создавать копии.

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

-felide-constructors

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

Получилось.
Ужасно.
.............................
Всем спасибо.
1
Kastaneda
Нарушитель
Эксперт С++
4676 / 2880 / 234
Регистрация: 12.12.2009
Сообщений: 7,314
Записей в блоге: 2
Завершенные тесты: 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 ===
0
kravam
быдлокодер
1700 / 887 / 45
Регистрация: 04.06.2008
Сообщений: 5,493
12.05.2011, 18:49  [ТС] #34
g++ -fno-elide-constructors

тогда по возврату из функции вызовется КК
(...Правда, я не знаю, какой у Вас компилятор.)
0
Kastaneda
Нарушитель
Эксперт С++
4676 / 2880 / 234
Регистрация: 12.12.2009
Сообщений: 7,314
Записей в блоге: 2
Завершенные тесты: 1
12.05.2011, 18:54 #35
Цитата Сообщение от kravam Посмотреть сообщение
g++ -fno-elide-constructors

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

Не по теме:

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

0
grizlik78
Эксперт С++
1964 / 1457 / 119
Регистрация: 29.05.2011
Сообщений: 3,016
27.06.2011, 00:51 #37
Цитата Сообщение от kravam Посмотреть сообщение
Угу? Ну ты согласишься, что если эта функция вызовется, то
всё-таки obj создастся?
Здесь я соглашусь. Объект создастся.
Цитата Сообщение от kravam Посмотреть сообщение
И не будет скопирован (как я хочу посимвольно),
И здесь так. Не будет скопирован.
Цитата Сообщение от kravam Посмотреть сообщение
и будет уничтожен
и будет вызван его деструктор?
Уничтожен-то будет, вопрос когда. Вот по коду приведённому в цитируемом посте совершенно очевидно, что уничтожен этот единственный объект будет по завершении функции main, так как имя этому объекту x, а вовсе не obj. Именно потому, что не вызывался конструктор копирования. Не стоит считать создателей компилятора недотёпами.
Цитата Сообщение от kravam Посмотреть сообщение
Вот, запусти и увидишь, что указатели указывают на один и тот же участок памяти. Уже удалённый, а нового нет, ибо МОЙ конструктор вызван не был.
Никто его пока не удалял. Его потом удалят.
Придумать ситуацию, когда RVO принесёт вред наверное можно, но очень не просто.
0
kravam
быдлокодер
1700 / 887 / 45
Регистрация: 04.06.2008
Сообщений: 5,493
27.06.2011, 01:17  [ТС] #38
Не стоит повторять. Там было уже сказано, что в данном примере (слишком простом) копирование излишне и так далее. И вообще.
0
kravam
быдлокодер
1700 / 887 / 45
Регистрация: 04.06.2008
Сообщений: 5,493
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;
}
0
asics
Freelance
Эксперт С++
2848 / 1783 / 144
Регистрация: 09.09.2010
Сообщений: 3,841
21.08.2011, 22:44 #40
Цитата Сообщение от kravam Посмотреть сообщение
//Вот эту херь надо то расскомментить, то закомментить, это КК и есть
//kl (kl const & o) {printf ("Вызов КК\n");}
Да ну...
0
grizlik78
Эксперт С++
1964 / 1457 / 119
Регистрация: 29.05.2011
Сообщений: 3,016
21.08.2011, 22:45 #41
Цитата Сообщение от kravam Посмотреть сообщение
Цирк да и только.
Согласен. Хоть бы версию компилятора указал. У меня поведение не меняется.
0
kravam
быдлокодер
1700 / 887 / 45
Регистрация: 04.06.2008
Сообщений: 5,493
21.08.2011, 23:01  [ТС] #42
Цитата Сообщение от asics Посмотреть сообщение
Да ну...
Баранки гну. Это для демонстрации только, что кк написан и он есть.

Добавлено через 38 секунд
Цитата Сообщение от grizlik78 Посмотреть сообщение
Согласен. Хоть бы версию компилятора указал. У меня поведение не меняется.
g++ (GCC) 3.4.2 (mingw-special)
0
Сыроежка
Заблокирован
22.08.2011, 17:04 #43
Цитата Сообщение от kravam Посмотреть сообщение
...У меня в книге описаны случаи при которых вызывается конструктор копирования. Один из этих случаев:

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

Ну-с попробуем смоделировать такую ситуацию:
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
grizlik78
Эксперт С++
1964 / 1457 / 119
Регистрация: 29.05.2011
Сообщений: 3,016
22.08.2011, 17:07 #44
Цитата Сообщение от Сыроежка Посмотреть сообщение
Никакой конструктор-копирования в вашем примере не должен вызываться, так как параметром вашей функции является константная ссылка на объект. То есть никакого нового объекта вы не создаете.
Ну хватит уже "капитанить", а? Это написано в первом же ответе на исходный пост, почти год назад.
1
Сыроежка
Заблокирован
22.08.2011, 17:08 #45
Цитата Сообщение от kravam Посмотреть сообщение
Стоп-стоп. Ребята, в этой же книге определён синтаксис конструктора копирования, а вы оба от него отошли. Синтаксис такой: (дословно)

"Синтаксис для объявления конструктора копирования следующий:
имя_класса (имя_класса const & источник)"

То есть надо именно так.

Unforgiven_00,
я Вам больше скажу, в книжке написано, что ваш вариант исползовать нельзя и даже описано почему нельзя. ПОка не буду на этом заострять внимания (если чё после аргументирую)

Итак, вопрос остаётся открытым
Мне стало очень любопытно, не могли бы вы пояснить, что там написано в книжке, что приведенный пример Unforgiven_00, не будет работать?!
0
22.08.2011, 17:08
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.08.2011, 17:08
Привет! Вот еще темы с ответами:

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

Почему вызывается конструктор, а не создание массива? - C++
struct KTest { KTest(int _a, double _b, long long _c) : a(_a), b(_b), c(_c) {} friend ostream&amp; operator &lt;&lt; (ostream&amp; os, KTest const&amp;...

Почему конструктор вызывается повторно при преобразовании типов? - C++
В качестве примера предлагаю рассмотреть примерчик из учебника. В примере мы создаём класс, содержащий в качестве поля строку символов и...

Почему конструктор вызывается при присвоении объекта другому объекту - C++
оператор+ выполняется нормально, но когда уже переменная в sum, на след шаге она вызывает конструктор, ибо у меня в примере 9 выходит. А в...


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

Или воспользуйтесь поиском по форуму:
45
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru