HighLander
|
|
« : 15-03-2011 07:45 » |
|
Здравствуйте!
У меня есть вопрос насчет памяти и где создаются локалиьниые переменниые.
Я работаю в Visual Studio 2008 и создаю C++ Win32 Application.
Я пишу класс, у которого есть функция, которая создает локально обьъект этого же класса.
Насколько я знаю, если я создаю обьъект локально, он создается в Стаке, правильно?
И я не могу вернуть из функции на него Reference, так как эта часть Стака исчезнет по окаончаниюи функции, правильно?
Или теперь локальниые переменниые тоже создаются в Хипе?
Зараниее благодарю!
|
|
« Последнее редактирование: 15-03-2011 09:38 от Джон »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #1 : 15-03-2011 07:48 » |
|
Всё как прежде: локальные переменные создаются на стеке. Динамически (на куче) выделяется память только под то, что само явно попросит, вызвав оператор new (или malloc).
Возврат из функции ссылки на локальную переменную приводит к неопределённому поведению: объект может никуда не исчезнуть, если стек не был перетёрт, но рассчитывать на корректность и неизменность этих данных категорически нельзя.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #2 : 15-03-2011 07:50 » |
|
Стаке это называется стек (stack). Вернуть ссылку можешь, только это бесполезно (хипы в Сатке, караул )
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #3 : 15-03-2011 07:50 » |
|
Номер версии Студии никак не меняет правил языка и win32 API. Объекты имеют следующие классы хранения: статический, автоматический (в стеке (stack)), динамический (в куче (heap))/ Ссылку можно вернуть на статический или динамический объект. Автоматические объекты уничтожаются при выходе из области видимости.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Вад
|
|
« Ответ #4 : 15-03-2011 07:51 » |
|
Исключения здесь, как и прежде, есть для статических переменных внутри функции: место под них выделяется специально, инициализация происходит, ЕМНИП, при первом входе в функцию. ЗЫ. RXL опередил
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #5 : 15-03-2011 07:51 » |
|
Как мы дружно...
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #6 : 15-03-2011 07:54 » |
|
инициализация происходит, ЕМНИП, при первом входе в функцию.
вернее, при первом вызове конструктора переменной
|
|
|
Записан
|
|
|
|
HighLander
|
|
« Ответ #7 : 15-03-2011 07:58 » |
|
Спасибо за ответы!
И это не важно на какой версии Windows запускать программу, да?
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #8 : 15-03-2011 08:05 » |
|
Если сама программа соответствует требованиям конкретной ОС (например, политике безопасности), то будет работать.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
HighLander
|
|
« Ответ #9 : 15-03-2011 08:13 » |
|
Я имею ввиду не влияет ли версия системы на то где создаются переменние?
И еще вопрос если можно: В C++ Managed, если я создаю обьект локально, он тоже создается в stack, да?
Тоесть в данном случае, это не имеет значения, да?
Спасибо!
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #10 : 15-03-2011 08:42 » |
|
Я имею ввиду не влияет ли версия системы на то где создаются переменние?
Не влияет, потому что код уже скомпилирован, и как-то по-другому, чем определил компилятор, он работать не может. И еще вопрос если можно: В C++ Managed, если я создаю обьект локально, он тоже создается в stack, да?
Если ты создаёшь не-managed-переменные - то всё то же самое, локальные идут на стек. Если ты создаёшь Managed-переменные (переменные managed-классов) - то их и не получится создать на стеке, они потребуют создания через gcnew, который определит их в специальную кучу, подконтрольную сборщику мусора.
|
|
|
Записан
|
|
|
|
HighLander
|
|
« Ответ #11 : 15-03-2011 09:16 » |
|
И не важно в каком Visual Studio я компилировал не-managed приложение, да?
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #12 : 15-03-2011 09:24 » |
|
По большому счёту - неважно. Детали оптимизации будут отличаться, но такие фундаментальные вещи, как локальные переменные и способ вызова функций - нет.
|
|
|
Записан
|
|
|
|
HighLander
|
|
« Ответ #13 : 15-03-2011 09:29 » |
|
Хорошо, огромное спасибо!
Добавлено через 1 день, 22 часа, 10 минут и 55 секунд: У меня есть еще не большой вопрос, если можно...
Если я делаю overload на оператор +, и в его функции я создаю новый обьект локально, то тут все как в и в простых функциях?
Тоесть тут также, обьект создается в стеке и если я верну reference на него то по оканчанию функции нет гарантии что обьект будет
жить, да?
Спасибо!
|
|
« Последнее редактирование: 17-03-2011 07:40 от HighLander »
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #14 : 17-03-2011 07:45 » |
|
дык
|
|
|
Записан
|
Странно всё это....
|
|
|
Вад
|
|
« Ответ #15 : 17-03-2011 07:45 » |
|
Жить он точно не будет, и нет никакой гарантии, что в стеке будет что-то разумное. На то он и стек.
|
|
|
Записан
|
|
|
|
HighLander
|
|
« Ответ #16 : 17-03-2011 07:51 » |
|
Тоесть если в overload на + я хочу вернуть новый обьект, я должен или вернуть копию локального или создать его в куче, да?
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #17 : 17-03-2011 08:19 » |
|
Лучше копию, иначе приходится много думать над удалением а можно вообще ничего не возвращать
а еще лучше опиши, что ты конкретно делаешь, в разных ситуациях разные критерия выбора решения
|
|
|
Записан
|
Странно всё это....
|
|
|
HighLander
|
|
« Ответ #18 : 17-03-2011 11:32 » |
|
Я просто хотел убедится что если я создаю в функции оператора обьект локально то он также создается в стеке как в любой функции и на
него нельзя вернуть reference.
Спасибо!
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #19 : 17-03-2011 11:47 » |
|
HighLander, а откуда возникло вот это сомнение насчёт того, что оператор - такая же функция, как и любая другая?
|
|
|
Записан
|
|
|
|
HighLander
|
|
« Ответ #20 : 17-03-2011 11:56 » |
|
На самом деле я всегда считал что в плане памяти функция оператора ведет себя как любая другая, но мне кто-то сказал что
в функции оператора можно создать локально обьект и вернуть на него reference.
Я хотел убедится что я прав в том что это не правильно, и даже если оно работает так только потаму что в эту часть стека еще никто
ничего не записал. (Так как по оканчанию функции эта память "уходит").
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #21 : 17-03-2011 12:07 » |
|
На самом деле, ссылки порой возвращают. Но в том случае, если объект не создаётся локально, а уже существует, и оператор является его методом. Тогда возвращают ссылку на сам объект, просто чтобы можно было выполнять цепочку операторов (например, a = b = c). Финты же со стеком в операторах могут закончиться плохо. Что будет, если эту "неушедшую" ссылку передать по ссылке в функцию? Type& operator+(const Type& l, const Type& r){ Type result; // do smth; return result; }
// .... void foo (const Type& boo){ boo.someMethod(); // кранты }
// ... Type a,b; foo(a + b); // передаём в функцию ссылку на временный уже уничтоженный объект Да и если ничего не вызывать - откуда программист может быть уверен, что его ссылкой никто не воспользуется в своих целях? Тем более что ссылка как раз для того и нужна, чтобы её использовать для чего-то такого.
|
|
« Последнее редактирование: 17-03-2011 12:11 от Вад »
|
Записан
|
|
|
|
HighLander
|
|
« Ответ #22 : 17-03-2011 13:56 » |
|
Тоесть вот так как вы вернули ссылку на result (созданный локально) из оператора возвращать нельзя, да?
|
|
|
Записан
|
|
|
|
Джон
просто
Администратор
Offline
Пол:
|
|
« Ответ #23 : 17-03-2011 14:04 » |
|
Скажем так, возвращать-то можно. Но что потом делать с таким оператором? Использовать его нельзя. Ведь объект result уже не существует.
|
|
|
Записан
|
Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома. "Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash "Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman "All science is either physics or stamp collecting." Ernest Rutherford "Wer will, findet Wege, wer nicht will, findet Gründe."
|
|
|
HighLander
|
|
« Ответ #24 : 17-03-2011 15:09 » |
|
Я это и имел ввиду. Спасибо за помощ!
|
|
|
Записан
|
|
|
|
HighLander
|
|
« Ответ #25 : 19-03-2011 09:08 » |
|
У меня еще один вопрос, если можно... Можно ли вернуть ссылку на локальный обьект если он после возвращения сразу переписывается? Например вот так: MyClass &operator+(const MyClass& other) { MyClass a; ... return a; } А там где я сипользую + я делаю: MyClass a, b, c; a = b + c; Получается что локальный обьект сразу перепишется, или это тоже не всегда будет работать?
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #26 : 19-03-2011 09:29 » |
|
так нельзя делать
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #27 : 19-03-2011 09:32 » |
|
HighLander, по-моему, ты занимаешься какой-то сомнительной оптимизацией. Если компилятор сочтёт нужным, он тут сам всё заоптимизирует, чтобы запись сразу происходила в новый объект, а не во временный. Даже если и не сочтёт - пока это не продавливает производительность приложения, смысла с этим что-то делать не вижу никакого. Хотя, может, у тебя какая-то специфическая задача?
И потом, не стоит думать, что вот ты напишешь небезопасный и абсолютно непредсказуемо себя ведущий код, и будешь использовать только в тех ситуациях и с тем компилятором, что поведение всегда будет такое, как тебе надо. Риск, что где-нибудь этот нерабочий грязный код будет использован не так, как ты изначально предполагал, намного превышает все выгоды, которые ты из этого пытаешься извлечь.
|
|
« Последнее редактирование: 19-03-2011 09:36 от Вад »
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #28 : 19-03-2011 09:58 » |
|
HighLander, опять тоже самое: нельзя возвращать ссылку на автоматический объект, созданный в самом методе или функции. Можно вернуть ссылку на: статический, динамический, параметр функции, *this. В твоем случае надо возвращать не ссылку, а копию. Если бы operator+ у тебя изменял this, то можно было бы вернуть ссылку на него. Так часто делают для облегчения каскадирования операций над объектом: class MyClass { private: int num; public: MyClass() : num(0) { } MyClass(int n) : num(n) { }
MyClass & add(const MyClass ¶m) { num += param.num; return *this; } };
MyClass a, b(1), c(2);
a.add(b).add(c);
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
HighLander
|
|
« Ответ #29 : 19-03-2011 12:48 » |
|
Спасибо за ответы!
Я понимаю о чем вы говорите, мне было просто интересно есть ли случаи когда можно вернуть ссылку на локальный обьект.
Еще раз спасибо!
|
|
|
Записан
|
|
|
|
|