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

Особенности использования указателей и ссылок в C++ при возврате из функции - C++

Восстановить пароль Регистрация
 
zer0mail
2180 / 1863 / 187
Регистрация: 03.07.2012
Сообщений: 6,627
Записей в блоге: 1
04.08.2013, 11:59     Особенности использования указателей и ссылок в C++ при возврате из функции #1
Пусть у нас есть некий класс CBase и есть функция, которая создает и возвращает объект класса CBase. Создать она его может стеке или в куче, а вернуть может сам объект, ссылку на него или указатель… Чем же различаются эти варианты? Для ответа напишем простой тест, использующий разные варианты и сравним.
Кликните здесь для просмотра всего текста

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
class CBase
{
public:
    int i;
    // конструктор по-умолчанию
    CBase()     
    {  
        i=0;
        name = NULL;  
        cout<<"Base() "<<endl;
    }
 
    CBase(const char *str1)     
    {  
        i=1;
        name = new char[strlen(str1)+1];  
        strcpy(name, str1); 
        cout<<"Base "<<i<<" "<<name<<endl;
    }
    // конструктор копирования, создает новую строку с добавлением @ в начале
    CBase(CBase &b)     
    {  
        i=2;
        name = new char[strlen(b.name)+2];  
        name[0]='@';
        strcpy(name+1, b.name); 
        cout<<"CopyBase "<<i<<" "<<name<<endl;
    }
    CBase & operator = (const CBase& b)
    {   i=3;
        cout<<"Base = "<<i<<" "<<name<<endl;
        return *this;
    }
    virtual ~CBase()                          
    { 
        cout<<"~Base "<<i<<" "<<name<<endl;
        delete [] name;
    }
    void SetString(const char *str1) {
        delete [] name;
        name = new char[strlen(str1)+1];  
        strcpy(name, str1); 
    }
protected:
    char *name;
};
 
class CDerived : public CBase
{
public:
    CDerived(const char *str1, const char *str2) 
        : CBase(str1)   
    { 
        name2 = new char[strlen(str2)+1];  
        strcpy(name2, str2);
        cout<<"Derived "<<name2<<endl;
    }
      ~CDerived()                                             
    {  
//      CBase::~CBase(); // а вот этого - не надо
        delete [] name2;
        cout<<"~Derived "<<name2<<endl;
    }
protected:
    char *name2;
};
 
// функции именуются так: get<символ возврата><символ создания>
//символ создания - как новый объект создается в процедуре:
// p - через new (p-указатель на созданный объект)
// o - через локальную переменную (o- локальная переменная)
//символ возврата - как новый объект возвращается в вызывающую процедуру:
// p - возвращается указатель на созданный объект
// о - возвращается сам созданный объект
// ro- возвращается ссылка на созданный объект
 
CBase *getpp(char* str) {
    CBase *p=new CBase(str);
    return p;
}
CBase getop(char* str) {
    CBase *p=new CBase(str);
    return *p;
}
CBase getoo(char* str) {
    CBase o(str);
    return o;
}
 
CBase& getrp(char* str) {
    CBase *p=new CBase(str);
    return *p;
}
 
CBase& getro(char* str) {
    CBase o(str);
    return o;
}
 
CBase* getpo(char* str) {
    CBase o(str);
    return &o;
}
 
void fun()
{
    CBase *pp=getpp("PP str1");     //+ новый объект создан в куче, на него вернули указатель. Потом надо не забыть удалить объект delete pp;
    CBase *po=getpo("PO str2");     //- локальный объект тут же удаляется, указатель на удаленный объек
    CBase op=getop("OP str3");      //- новый объект создан в куче, потом он копируется. НО старый объет остался в куче, т.е произошла утечка памяти
    CBase oo=getoo("OO str4");      //+ новый объект копируется, локальный удаляется. ВСЕ ОК. 
    CBase oro=getro("ORO str5");    //- локальный объект сначала удаляется, потом копируется! тяжелый случай
    CBase orp=getrp("ORP str6");    //- новый объект создан в куче, потом он копируется. НО старый объет остался в куче, т.е произошлаа утечка памяти
    CBase &rro=getro("RRO str7");   //- локальный объект тут же удаляется, ссылка на удаленный объект
    CBase &rrp=getrp("RRP str8");   //+ новый объект создан в куче, на него вернули ссылку. Но его надо не забыть удалить delete &rrp
    CBase o=oo; // копируется
    o=orp; // копируется
    
    // удаление объектов
    delete pp;
    delete &rrp; // ручное
    cout<<"Конец функции"<<endl;
}

А вот результат выполнения fun(), на основании которого сделаны комментарии:
Кликните здесь для просмотра всего текста

Base 1 PP str1
Base 1 PO str2
~Base 1 PO str2
Base 1 OP str3
CopyBase 2 @OP str3
Base 1 OO str4
CopyBase 2 @OO str4
~Base 1 OO str4
Base 1 ORO str5
~Base 1 ORO str5
CopyBase 2 @H€A
Base 1 ORP str6
CopyBase 2 @ORP str6
Base 1 RRO str7
~Base 1 RRO str7
Base 1 RRP str8
CopyBase 2 @@OO str4
Base = 3 @@OO str4
~Base 1 PP str1
~Base 1 RRP str8
Конец функции
~Base 3 @@OO str4
~Base 2 @ORP str6
~Base 2 @H€A
~Base 2 @OO str4
~Base 2 @OP str3

Выводы:
Из 8 рассмотренных вариантов осталось 3.
1-й и 8-й варианты создают объект в куче, нет копирования (не тратится время). НО их надо удалять.
4-й тоже неплох (если знаешь, как происходит копирование и объект небольшой).

В общем 1-й и 4-й варианты работают так, словно объект создан через конструктор.
А 8-й удобен в плане использования: обращение к полям через точку '.' (как в 4), но необходимость удаления объекта неочевидна.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Jupiter
Каратель
Эксперт C++
6542 / 3962 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
04.08.2013, 12:01     Особенности использования указателей и ссылок в C++ при возврате из функции #2
и??
zer0mail
2180 / 1863 / 187
Регистрация: 03.07.2012
Сообщений: 6,627
Записей в блоге: 1
04.08.2013, 12:30  [ТС]     Особенности использования указателей и ссылок в C++ при возврате из функции #3
И все Тема для чтения и для того, чтобы давать на нее ссылки (а не объяснять много раз одно и то же).
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
04.08.2013, 12:32     Особенности использования указателей и ссылок в C++ при возврате из функции #4
А для того, чтобы не греть голову на тему "кто это должен удалять?", "как быть с копированием больших объектов?" были придуманы такие вещи как rvalue-ссылки, move-конструкторы и операторы присваивания, а также умные указатели.
zer0mail
2180 / 1863 / 187
Регистрация: 03.07.2012
Сообщений: 6,627
Записей в блоге: 1
04.08.2013, 12:38  [ТС]     Особенности использования указателей и ссылок в C++ при возврате из функции #5
Я в курсе. А еще придумали кучу языков, где нет указателей. Кто не хочет греть - пусть проходит мимо
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
04.08.2013, 12:42     Особенности использования указателей и ссылок в C++ при возврате из функции #6
Т.е. автор описывает возможные варианты, рассказывает каких проблем мы огребем во всех случаях, но игнорирует прямые решения этих проблем. Ок, молчу.
zer0mail
2180 / 1863 / 187
Регистрация: 03.07.2012
Сообщений: 6,627
Записей в блоге: 1
04.08.2013, 12:52  [ТС]     Особенности использования указателей и ссылок в C++ при возврате из функции #7
1. Я в курсе других вариантов. А еще придумали кучу языков, где нет указателей.
2. Не надо молчать - никто не запрещает создать тему и рассмотреть в ней примеры с умными указателями rvalue-ссылками и т.п.
3. Если в проекте используются сотни фукций без "умных указателей" - будешь переписывать их все?
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
04.08.2013, 12:55     Особенности использования указателей и ссылок в C++ при возврате из функции #8
Цитата Сообщение от zer0mail Посмотреть сообщение
3. Если в проекте используются сотни фукций без "умных указателей" - будешь переписывать их все?
Из смартпоинтера всегда можно получить обычный указатель. Если же в боевом проекте на С++ изначально везде используется ручное управление памятью, это уже серьезный повод хорошо задуматься на тему адекватности такого решения.
zer0mail
2180 / 1863 / 187
Регистрация: 03.07.2012
Сообщений: 6,627
Записей в блоге: 1
04.08.2013, 13:06  [ТС]     Особенности использования указателей и ссылок в C++ при возврате из функции #9
Я по образованию физик. А физики используют компьютер как инструмент расчетов, а не как средство демонстрации своей программистской крутизны. И полно библиотек написано на простом Си или С++ с простыми указателями, переписывать которые никто не собирается. А есть даже написанные на Фортране (и немало).

Если найдутся желающие заменить систему управления ядерным реактором на новую, с "современными смарт-указателями", то скорее заменят этих желающих, а не систему.
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
04.08.2013, 13:07     Особенности использования указателей и ссылок в C++ при возврате из функции #10
Цитата Сообщение от zer0mail Посмотреть сообщение
А физики используют компьютер как инструмент расчетов, а не как средство демонстрации своей программистской крутизны.
Не в крутизне дело, а в упрощении кода.
Цитата Сообщение от zer0mail Посмотреть сообщение
И полно библиотек написано на простом Си или С++ с простыми указателями, переписывать которые никто не собирается.
И это нормально. Но использование в проекте сторонней библиотеки не означает, что нужно полностью перенимать ее стиль.
zer0mail
2180 / 1863 / 187
Регистрация: 03.07.2012
Сообщений: 6,627
Записей в блоге: 1
04.08.2013, 13:09  [ТС]     Особенности использования указателей и ссылок в C++ при возврате из функции #11
Не так давно в интернете были вакансии программистов для АЭС в Канаде. Так программы и компьютеры там 30-летней давности и планируют их эксплуатировать до 2050 года.
IGPIGP
Комп_Оратор)
 Аватар для IGPIGP
6162 / 2891 / 282
Регистрация: 04.12.2011
Сообщений: 7,691
Записей в блоге: 3
04.08.2013, 13:23     Особенности использования указателей и ссылок в C++ при возврате из функции #12
zer0mail, дружище вот тут в 8-м варианте:
C++
1
2
3
4
CBase* getpo(char* str) {
    CBase o(str);
    return &o;
}
возврат ссылки на локальную переменную.
Вообще, указатель, ссылка и переменная-значение дают массу вариантов передачи и возврата. Передача по ссылке, кроме всего ещё и не всегда передача типа-ссылки. Если добавить к этому варианты с вновь создаваемыми объектами, то это будет книга. А дальше, - указатели на полиморфные типы... Не подъёмно.
Даже если не описывать задачу для каждого случая. То есть не пытаться обосновать, а когда вот так сделать лучше чем эдак. Не лучше ли рассматривать каждый случай отдельно?
zer0mail
2180 / 1863 / 187
Регистрация: 03.07.2012
Сообщений: 6,627
Записей в блоге: 1
04.08.2013, 13:45  [ТС]     Особенности использования указателей и ссылок в C++ при возврате из функции #13
Спасибо, IGPIGP, не забываешь . В 8-м тесте вызывается getrp и объект создается в куче, так что ссылка на него корректна.
А getpo вызывается во 2-м тесте и я пишу, что она не подходит (поскольку объект сразу удаляется).

Проблема может быть с 5-м тестом, кода сначала удаление а потом компирование (программа может просто "вылететь").
IGPIGP
Комп_Оратор)
 Аватар для IGPIGP
6162 / 2891 / 282
Регистрация: 04.12.2011
Сообщений: 7,691
Записей в блоге: 3
04.08.2013, 13:49     Особенности использования указателей и ссылок в C++ при возврате из функции #14
Цитата Сообщение от zer0mail Посмотреть сообщение
А в 8-м тесте вызывается getrp и объект создаетсся в куче, так что ссылка на него корректна.
Верно, я запутался в подсчете, да и записано у Вас в комментарии всё. Извините.
zer0mail
2180 / 1863 / 187
Регистрация: 03.07.2012
Сообщений: 6,627
Записей в блоге: 1
04.08.2013, 13:52  [ТС]     Особенности использования указателей и ссылок в C++ при возврате из функции #15
Да не за что - я рад, что ты читаешь мои опусы хотя бы тут (в физику я давно не пишу).
IGPIGP
04.08.2013, 13:55
  #16

Не по теме:

Цитата Сообщение от zer0mail Посмотреть сообщение
Да не за что - я рад, что ты читаешь мои опусы хотя бы тут (в физику я давно не пишу).
дык, тихо там стало, - лето. К осени жизнь вернётся.

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.08.2013, 13:58     Особенности использования указателей и ссылок в C++ при возврате из функции
Еще ссылки по теме:

Использование ссылок и указателей C++
C++ В чём смысл использования указателей на функции
Ступор в возврате указателей и ссылок C++

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

Или воспользуйтесь поиском по форуму:
zer0mail
2180 / 1863 / 187
Регистрация: 03.07.2012
Сообщений: 6,627
Записей в блоге: 1
04.08.2013, 13:58  [ТС]     Особенности использования указателей и ссылок в C++ при возврате из функции #17
Классы, объекты, указатели, ссылки - фундаментальные понятия в C++ и все программисты должны четко представлять, что это такое и как их готовить (сам не используешь - так дадут код, где их используют).
Ссылки - они как фотон дуальны: с одной стороны как объект (типа частица), с другой - как указатель (типа волна)
Yandex
Объявления
04.08.2013, 13:58     Особенности использования указателей и ссылок в C++ при возврате из функции
Ответ Создать тему
Опции темы

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