Указатель на локальную переменную
"Не возвращайте указатели или ссылки на локальные переменные!".
Но ведь иногда бывает так, что результат формируется внутри функции и приходится там заводить какую-то переменную result, а потом возвращать её, например:
char* GetString(int i)
{
char *result=new char[255];
switch(i)
{
case 1:result="My name is Vasya!";break;
case 2:result="dasddfasdf";break;
}
return result;
}
или что-то вроде такого,
но ведь этот код некоректен.
Как лучше оформлять подобный код?
Как лучше оформлять подобный код?
Твой код сожержит ошибку, которая приводит к memory leak и потенциально к access violation.
Правильно будет так:
{
switch(i)
{
case 1:
return "My name is Vasya!";
case 2:
return "dasddfasdf";
}
}
или так:
{
switch(i)
{
case 1:
return "My name is Vasya!";
case 2:
return "dasddfasdf";
}
}
Маленикое уточнение:
... потому, что ты вызываешь operator= (char *, char *), т.е. присваиваешь один указатель другому, поэтому тот, который содержал адрес выделеной тобой памяти будет утерян.
case 1: result=...; // первоначаьное значение утеряно
Нужно либо копировать строки ( strcpy(), strncpy() )
Либо пользоваться классами, тогда за тебя это сделает STL
Либо пользоваться классами, тогда за тебя это сделает STL
Угу. Так и есть.
если можно поподробнее, прокоментируй
pr proc
push ebp
mov ebp, esp
;и тут вот локальная переменная, например типа int со значением 10
push 10
;и вот ее использование:
mov eax, [ebp-4];примерно так, насчет 4 не уверен
Это к тому, что стек - обыкновенная область памяти, и доступ к нему идет также долго, как и при обращении к памяти (если не принимать во внимание существование кэш-памяти).
{
int * dinamic = new int[1000];
dinamic[25] = 3;
return 0;
}
Дизасемблируем
004113AE push 0FA0h
004113B3 call operator new (411177h)
004113B8 add esp,4
004113BB mov dword ptr [ebp-0D4h],eax
004113C1 mov eax,dword ptr [ebp-0D4h]
004113C7 mov dword ptr [dinamic],eax
// dinamic[25] = 3;
[COLOR="Red"]004113CA mov eax,dword ptr [dinamic]
004113CD mov dword ptr [eax+64h],3 [/COLOR]
Далее
{
int stek[1000];
stek[25] = 3;
return 0;
}
Дизассемблируем
//stek[25] = 3;
[COLOR="#ff0000"]004113B2 mov dword ptr [ebp-0F40h],3 [/COLOR]
Это Visual C++ 2005. Возможно в другом компиляторе будут отличия, но суть останется той же. Стековая память имеет фиксированный размер и указатель на стек, специально предназначенный для быстрого доступа к стековым данным. С динамической памятью все подругому.
Особенно быстро производится работа со стековыми массивами, так как адрес начала массива в стеке постоянный. Особенно если индекс задан константой - в этом случае адрес элемента определяется как "ebp-X", где смещение вычисляется ещё на этапе компиляции.
Для массива в куче ВСЕГДА требуется сначала получить адрес начала массива из элемента стека, а потом прибавить к нему смещение.
Вот только символьные массивы часто приводят к ошибкам :(. То access violation, то переполнение буфера... Используйте лучше строковые объекты.
Из-за дури писавшего :-D
Еще юзайте stl, tr1, boost, не забывая шаблоны проектирования в программах уровня хеллоу ворлд - это же так интересно. :-D
PS: Особенно интересно использовать объекты с константными строками, обернутые в stl::map с ключем-индексом :-D
Из элемента стека? Заполни мой пробел пожалуйста, мне казалось стёкавая память отличается свойством thread - safe, то есть при вызове функцией другой нитью (потоком) стековые данные пушаться в стек, и создается новый набор локальных данных. (по сути при вызове любой рекурсивной функции, просто как пример)
А если у нас указатель на динамическую область памяти объявлен вне функции, то указатель хранится где-то в статической памяти (вот здесь я не совсем понимаю где это?).
Просвети =)
const char* GetString(int i)
{
char* result=new char[100];
switch(i)
{
case 1:
strcpy(result,"какая-то строка");
case 2:
strcpy(result,"какая-то строка");
}
return result;
}
но ведь нужно освободить память, занятую result.В каком месте это сделать?
Тот на котором ты остановился не самый то что надо =), ты это видишь уже потому что сразу наступаешь на еще одни грабли.
Касательно именно этого вопроса могу посоветовать передовать внешний указатель в функцию а память выделять и освобождать по месту использования. void GetString(int i, char* t).
Но!
Лучше используй один из вариантов Green`а.
{
"Suxx1",
"Suxx2"
};
const char* GetString(unsigned int i)
{
const char* pRet = NULL;
if (i < 2)
pRet = g_aString;
return pRet;
}
{
const char* pRet = NULL;
static const char* aString[] =
{
"Suxx1",
"Suxx2"
};
if (i < 2)
pRet = aString;
return pRet;
}
Но вспомните эпопею с EuroDiff, где выяснилось, что держать массивные данные на стеке накладно для производительности. Особенно яркр это проявилось на Celeron.
http://forum.codenet.ru/showthread.php?t=17339&page=13
PS: Спасибо за единственный умный комментарий.
PS2: А если объявить его так "static const char* const aString[] = ...", то он еще будет в секции данных только для чтения.
Из элемента стека?
[/quote]
А откуда же ещё? :) Обращение к объектам (массивам), которые расположены в областях памяти, отличных от сегмента стека текущей функции, производится через адреса, хранимые в локальных указателях или ссылках. Или по цепочке (объект1->объект2->объект3), начало которой всё равно расположено в стеке функции. Иначе - утечка памяти
Исключение составляют только глобальные и статические переменные (константы), адреса которых известны на момент компиляции.
[quote=Green]
Обращение, что к куче, что к стеку, занимает одинаковое время.
[/quote]
Это в циклах, когда адрес начала массива заранее считан из стека в регистр CPU.
А при единичном доступе по заранее определённым индексам вызываются ДВЕ команды вместо одной. Правда, подобный доступ используется ОЧЕНЬ редко.
А у него кэш маленький - весь стековыми массивами заполнялся :D