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

Конструкторы и механизм return - C++

Восстановить пароль Регистрация
 
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
04.04.2014, 15:05     Конструкторы и механизм return #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
#include <iostream>
 
using namespace std;
 
struct M
{
    M() { cout << "1\n"; }
    M(const M&) { cout << "2\n"; }
    M& operator=(const M&) { cout << "3\n"; return *this; }
    ~M() { cout << "4\n"; }
    int a[10000];
};
 
M func()
{
    M x;
    return x; 
}
 
int main()
{
     M y = func();
}
Почему выводится 1 4? MSVS 2012
По логике, должен вызваться конструктор объекта x, этот объект вернет свою копию. Затем будет вызван копирующий конструктор объекта y. Будет вызван деструктор для x, потом для y. Может компилятор так соптимизил...

Добавлено через 19 минут
gcc тоже самое выводит
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
dzrkot
zzzZZZ...
 Аватар для dzrkot
516 / 346 / 53
Регистрация: 11.09.2013
Сообщений: 1,977
04.04.2014, 15:07     Конструкторы и механизм return #2
в функции вызывается конструктор по-умолчанию, вы создаете y и присваеваете ему объект с конструктором по-умолчанию - отсюда 1, потом деструктор - 4
Vourhey
Почетный модератор
6468 / 2243 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
04.04.2014, 15:12     Конструкторы и механизм return #3
Цитата Сообщение от Dani Посмотреть сообщение
Может компилятор так соптимизил...
Да.

Добавлено через 4 минуты
Цитата Сообщение от dzrkot Посмотреть сообщение
вы создаете y и присваеваете ему объект с конструктором по-умолчанию - отсюда 1
1 из
Цитата Сообщение от dzrkot Посмотреть сообщение
в функции вызывается конструктор по-умолчанию
По поводу
Цитата Сообщение от dzrkot Посмотреть сообщение
потом деструктор - 4
Нет, потом конструктор копирования по возвращению из функции, а потом уже деструктор.
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
04.04.2014, 15:13  [ТС]     Конструкторы и механизм return #4
если уж
Цитата Сообщение от dzrkot Посмотреть сообщение
присваеваете
то должен был бы вызваться operator=
Vourhey
Почетный модератор
6468 / 2243 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
04.04.2014, 15:14     Конструкторы и механизм return #5
Цитата Сообщение от Dani Посмотреть сообщение
gcc тоже самое выводит
Собери без оптимизации.
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
04.04.2014, 15:14  [ТС]     Конструкторы и механизм return #6
Сейчас попробую
Vourhey
Почетный модератор
6468 / 2243 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
04.04.2014, 15:14     Конструкторы и механизм return #7
Цитата Сообщение от Vourhey Посмотреть сообщение
а потом уже деструктор.
имею ввиду деструктор для x. Само собой, потом деструктор для y.
Ilot
Модератор
Эксперт С++
1767 / 1142 / 223
Регистрация: 16.05.2013
Сообщений: 3,020
Записей в блоге: 5
Завершенные тесты: 1
04.04.2014, 15:17     Конструкторы и механизм return #8
Скорее всего оптимизация. Если немного попытаться обмануть компилятор то все получится как положенно:
Кликните здесь для просмотра всего текста

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
#include <iostream>
using namespace std;
struct M
{
    M() { cout << "1\n"; }
    M(const M&) { cout << "2\n"; }
    M& operator=(const M&) { cout << "3\n"; return *this; }
    ~M() { cout << "4\n"; };
    M& operator+(int t) {
        r += t;
        return *this;
    }
    int r;
};
M func()
{
    M x;
    return x + 1;
}
 
int main()
{
    M y = func();
    return 0;
}
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
04.04.2014, 15:19  [ТС]     Конструкторы и механизм return #9
Цитата Сообщение от Vourhey Посмотреть сообщение
Собери без оптимизации.
А как в gcc отключить оптимизации? Вроде бы без -O2 и всяких свистелок компилю.
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
04.04.2014, 15:19     Конструкторы и механизм return #10
Оптимизация бывает разная. Тут в частности срабатывает вот это:
http://stackoverflow.com/questions/9...al-studio-2010
Еще для поиска: no-elide-constructors
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
04.04.2014, 15:24  [ТС]     Конструкторы и механизм return #11
В студии отключил отпимизации, получилось 1 2 4 4

Добавлено через 2 минуты
А как вообще можно заставить компилятор не оптимизировать здесь? Т.е. есть проект, включена оптимизация, но в таких местах, допустим, критически важен вызов копирующего конструктора, как заставить компилятор здесь не оптимизировать?
Vourhey
Почетный модератор
6468 / 2243 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
04.04.2014, 15:25     Конструкторы и механизм return #12
Цитата Сообщение от Dani Посмотреть сообщение
А как вообще можно заставить компилятор не оптимизировать здесь?
У тебя в программе нет места, где был бы важен вызов копирующего конструктора, поэтому компилятор оптимизирует.
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
04.04.2014, 15:30  [ТС]     Конструкторы и механизм return #13
Vourhey, даже если я сделаю так M(const M&) { a[1] = 14; cout << "2\n"; }, все равно 1 4. Хотя тут идет важная часть (присвоение 14). Или что имеется ввиду под выражением "важная часть"?
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
04.04.2014, 15:41     Конструкторы и механизм return #14
Цитата Сообщение от Dani Посмотреть сообщение
А как вообще можно заставить компилятор не оптимизировать здесь?
По ссылке, что я привел, написано, что для студии никак. Для gcc -fno-elide-constructors
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
04.04.2014, 15:47  [ТС]     Конструкторы и механизм return #15
Только что запустил для gcc: получилось 1 2 4 2 4 4. То есть: в func() запускается конструктор объекта x, x копируется копирующим конструктором во временной объект, затем x удаляется, запускается копирующий конструктор для y, который копирует значения из временного объекта, затем временный объект удаляется, потом удаляется y. Правильно?
Vourhey
Почетный модератор
6468 / 2243 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
04.04.2014, 15:54     Конструкторы и механизм return #16
Цитата Сообщение от Dani Посмотреть сообщение
Или что имеется ввиду под выражением "важная часть"?
C++
1
2
3
4
5
M func()
{
    M x;
    return x; 
}
Это создание объекта по умолчанию, и используется объект только внутри функции. То есть, он не важен ни в одно части программы. Поэтому при оптимизации твоего кода x можно вообще убирать и работать с одним y.
Думаю, что если добавить static перед M x;, то оптимизатор не станет убирать x Это не решение, это просто пример, почему оптимизатор убирает x.
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
04.04.2014, 16:01  [ТС]     Конструкторы и механизм return #17
Поставил static. Скомпилил в gcc без опций: вывод 1 2 4 4. Скомпилил в gcc с -fno-elide-constructors, получилось 1 2 2 4 4 4. Куда делать еще одна двойка и четверка при компиляции без опций? Обходимся без временного объекта? Как тогда это происходит?
Vourhey
Почетный модератор
6468 / 2243 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
04.04.2014, 16:07     Конструкторы и механизм return #18
Цитата Сообщение от Dani Посмотреть сообщение
Обходимся без временного объекта? Как тогда это происходит?
Просто. Например:
C++
1
2
3
4
5
6
7
8
M func()
{
    M x;
    x.a[1] =10;
    return x; 
}
 
M y =  func();
Спокойно может быть сокращено до, грубо:
C++
1
2
M y;
y.a[1] = 10;
с точки зрения результата - идентично.
Dani
1263 / 621 / 50
Регистрация: 11.08.2011
Сообщений: 2,236
Записей в блоге: 2
Завершенные тесты: 1
04.04.2014, 16:13  [ТС]     Конструкторы и механизм return #19
Вот нашел здесь такое: http://rsdn.org/forum/cpp/1436516.all
А>1.

C++
1
2
3
4
5
6
int f(){
  int y = 5;
  return 5;
}
 
a  = f(); //вот тут вычислится значение f - выделится память на int и после присвоения - освободится

большинство реализаций скомпилируют это так, что f вернёт значение в каком-нибудь предназначенном для этого месте проца, например в специальном регистра. На Intel это обычно eax. оттуда это значение и будет сохранено в переменную a.


А>2.


C++
1
2
3
4
5
const char* f(){
 return "qwe";
}
 
const char *str = f(); // Что вот тут будет? Какая память выделяется и что с ней дальше происходит?

Строчка "qwe" выделится в сегменте статических данных и будет там спокойно жить, когда функция затеет его возвращать, она вернёт просто сам указатель, то есть тоже как атомарное значение, то есть всё будет очень похоже на п 1, только значение будет передаваться другое. Оно же и сохранится в str.
Правда есть одно замечание. В C++ "qwe" имет тип const char [4], так что чтобы всё было по стандарту, нужно писать ещё и выделенное полужирным const

А>3.


C++
1
2
3
4
5
6
char* f(){
 char qw[] = "qwe";
 return qw;
}
 
char *str = f(); // Что вот тут будет? Какая память выделяется и что с ней дальше происходит?

А вот тут будет плохо!

char qw[] = "qwe"; -- это объявление автоматического массива из 4-х char'ов, и инициализация его кодами букв q, w, e и 0.
После чего адрес этого массива (то есть адрес данных на стеке), будет возвращён из функции так же как был возвращён адрес во втором случае. Но, так как стековый фрейм f будет к этому моменту разрушен, то эти данные довольно скоро будет затёрты какими-нибудь другими пользователями стека, так что вы получити какой-то мусор.

Но есть ещё и
4

C++
1
2
3
4
5
6
7
8
9
10
11
12
struct IntData {
   int Size;
   int Data[15];
};
 
IntData f() {
   IntData result;
   //  тут как-то инициализируют поля переменной result
   return result;
}
 
IntData data = f(); // Что вот тут будет? Какая память выделяется и что с ней дальше происходит?

Произойдёт интересно.
Так как структура IntData довольно большая, то она уже скорее всего не сможет быть передана через "волшебное место" в процессоре, так что она будет передаваться через память. Обычно это происходит так:
1) Тот кто вызывает, заводит у себя место под возвращаемое значние функции. Если компилятор не совсем того, то в данном контексте это будет непосредственно место под переменную data.
2) у функции f() на самом деле есть тайный параметр, куда передаётся указатель на это место
3) в операторе return будет вызван конструктор IntData, при этом объект будет сконструирован как раз в том самом месте. В этом варинте функции позовут конструктор копирования.
4) Вызывающая сторона сама решает как распорядиться полученным временным объектом. В жанном варианте (если компилятор не совсем того), то временного объекта вообще не будет и мы просто получим инициализированную переменную data и программа продолжит выполнение.

Сообщение довольно старое. Этому можно верить? Сейчас тоже так все происходит?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.04.2014, 16:18     Конструкторы и механизм return
Еще ссылки по теме:

механизм присваивания в С++ C++
C++ Механизм замещения
C++ Механизм перегрузки

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

Или воспользуйтесь поиском по форуму:
Vourhey
Почетный модератор
6468 / 2243 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
04.04.2014, 16:18     Конструкторы и механизм return #20
Цитата Сообщение от Dani Посмотреть сообщение
Сообщение довольно старое. Этому можно верить? Сейчас тоже так все происходит?
Да.
То, что я написал про
Цитата Сообщение от Vourhey Посмотреть сообщение
M y;
y.a[1] = 10;
Если вдаваться в детали, то вызов func все равно может быть в наличии. Но работать он будет с объектом постоянным, а не временным. Но для простоты я написал так, чтобы объяснить, почему не будет конструктора копирования
Yandex
Объявления
04.04.2014, 16:18     Конструкторы и механизм return
Ответ Создать тему
Опции темы

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