Плохо ли выделить в функции память для некоторой динамической переменной, а затем вернуть ссылку на неё?
Когда в таком случае будет освобождена (или как можно будет освободить) память из под неё?
Re: ссылка на динамическую переменную
От:
Аноним
Дата:
14.10.04 11:52
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Плохо ли выделить в функции память для некоторой динамической переменной, а затем вернуть ссылку на неё? А>Когда в таком случае будет освобождена (или как можно будет освободить) память из под неё?
Ничего плохого, если там, куда вернешь ссылку или еще где-то (где тебе нужно) не забудешь освободить память.
Здравствуйте, Аноним, Вы писали:
А>Плохо ли выделить в функции память для некоторой динамической переменной, а затем вернуть ссылку на неё? А>Когда в таком случае будет освобождена (или как можно будет освободить) память из под неё?
using namespace std;
class A{
};
int main(){
A* ptr = new A;
A& ref = *ptr;
delete &ref;
}
Здравствуйте, Аноним, Вы писали:
А>Плохо ли выделить в функции память для некоторой динамической переменной, а затем вернуть ссылку на неё?
Все зависит от контекста.
А>Когда в таком случае будет освобождена (или как можно будет освободить) память из под неё?
В этом случае вся ответственность на тебе (ну или на пользователе этой функции).
Чтобы освободиться от этой ответственности, обычно используются умные указатели.
Здравствуйте, Аноним, Вы писали:
А>Плохо ли выделить в функции память для некоторой динамической переменной, а затем вернуть ссылку на неё? А>Когда в таком случае будет освобождена (или как можно будет освободить) память из под неё?
Ты имеешь в виду
int& foo() { int*p=new int(123); return *p; }
int& bar() { static int v=123; return v; }
int main()
{
int& f = foo();
int& b = bar();
f += b; b -= f; f += b;
delete &f;
}
С точки зрения компилятора — ничего криминального нет. Но делать так — однозначно не стоит!
Во-первых, заподло для сопровождения программы. Почему память из-под ссылки f нужно удалять, а из-под b — нельзя?
Во-вторых, проблема с перегруженным оператором &
struct figvam
{
char c[1000];
int x;
int* operator& () { return &x; }
};
figvam& fig() { return *new figvam; }
int main()
{
figvam& f = fig();
delete &f; // &f имеет тип int* и указывает бог весть куда
}
В-третьих, элементарная забывчивость (см. "во-первых")
Имею почти такую же ситуацию. Есть класс в нем функция, которая выделяет память, а освобождаю память по завершению работы этой функции в коде основной процедуры.
...
class A
{
void f(BYTE** ppData){ *ppData = (BYTE*)malloc(need_size);}
};
...
main()
{
BYTE* b;
A clsA;
clsA.f(&b);
....
free(b);
}
В таком виде, как в примере — работает замечательно. Но, если класс А "засунуть" в DLL при попытке освобождения памяти free(b) вылетает ошибка. Т.к. я не знаток работы с DLL, то не знаю почему и из-за чего это происходит. Если же добавить в класс А в DLL свою функцию:
void А::Free(BYTE* pData){free(pData);}
и вызывать ее:
main(){ ... clsA.Free(b); ...}
То ошибки не появляется.
Почему появляется ошибка про которую я говорил раньше?
Здравствуйте, Аноним, Вы писали:
А>Плохо ли выделить в функции память для некоторой динамической переменной, а затем вернуть ссылку на неё?
Лучше вернуть указатель.
Потому что когда видишь функцию, возвращающую указатель, сразу возникает вопрос: "Кто будет память освобождать?"
С функцией же, возвращающей ссылку, такая мысль в голову не придет (буквально вчера или сегодня в нашем проекте обнаружилась точно такая же проблема — все долго смеялись, ибо никому даже в голову не пришло освободить полученную по ссылке память).
А>Когда в таком случае будет освобождена (или как можно будет освободить) память из под неё?
Здравствуйте, mihauzen, Вы писали:
M>Имею почти такую же ситуацию. Есть класс в нем функция, которая выделяет память, а освобождаю память по завершению работы этой функции в коде основной процедуры.
M>В таком виде, как в примере — работает замечательно. Но, если класс А "засунуть" в DLL при попытке освобождения памяти free(b) вылетает ошибка. Т.к. я не знаток работы с DLL, то не знаю почему и из-за чего это происходит. Если же добавить в класс А в DLL свою функцию:
M>void А::Free(BYTE* pData){free(pData);}
M>и вызывать ее: M>То ошибки не появляется. M>Почему появляется ошибка про которую я говорил раньше?
Ага! Так сразу бы и сказал
История в том, что функции malloc/free — это интерфейс некоей сущности "менеджер кучи", которая живёт в CRT.
Если твои DLL и/или EXE прилинковывают CRT статически, то в связке EXE+DLL оказываются два экземпляра этого менеджера.
Ты выделяешь память в одном, а убиваешь в другом, приводя его в изумление.
Когда же ты написал экспортируемую функцию A::Free (определённую в DLL), она обращается к тому же менеджеру, что и выделял память.
Как лечить?
* Использовать глобальный менеджер кучи, предоставляемый системой. Например, в COM-приложениях это TaskMemAlloc/TaskMemFree.
* Линковать CRT динамически во всех модулях (см. опции компилятора | настройки проекта)
Здравствуйте, Кодт, Вы писали:
К>Как лечить? К>* Использовать глобальный менеджер кучи, предоставляемый системой. Например, в COM-приложениях это TaskMemAlloc/TaskMemFree.
CoTaskMemAlloc/CoTaskMemFree
Но лучше тогда уж использлвать Default Heap. Доступ к нему можно получить вызовом GetProcessHeap.
Здравствуйте, <Аноним>, Вы писали:
А>Плохо ли выделить в функции память для некоторой динамической переменной, а затем вернуть ссылку на неё? А>Когда в таком случае будет освобождена (или как можно будет освободить) память из под неё?
В подобных случаях можно рассмотреть альтернативу -- переменную создавать в вызывающей процедуре и передавать ссылку на неё вызываемой, что бы та заполнила переменную требуемым значением.
В этом случае нередко можно обойтись без динамической памяти и появляется дополнительная гибкость -- метод размещения переменной не прошит жестко в функции, а может быть выбран вызывающей процедурой.
Здравствуйте, Аноним, Вы писали:
А>Плохо ли выделить в функции память для некоторой динамической переменной, а затем вернуть ссылку на неё? А>Когда в таком случае будет освобождена (или как можно будет освободить) память из под неё?
Здравствуйте, Аноним, Вы писали:
А>Плохо ли выделить в функции память для некоторой динамической переменной, а затем вернуть ссылку на неё?
Плохо. Уже говорили тут, что никому не придёт в голову освободить память.
Полезнее будет сделать примерно так:
class A
{
// ...public:
A(/*...*/);
};
std::auto_ptr<A> makeA(/*...*/)
{
// ...;return std::auto_ptr<A>(new A(/*...*/));
}
int main(int, char**)
{
{
std::auto_ptr<A> a = makeA(/*...*/);
// здесь что-то делаем с *a
} // здесь a выходит из области видимости, деструктируется и память освобождается
// а вот тут попробуем проигнорировать возвращаемое значение
makeA(/*...*/); // 1. нам вернули временный объект класса std::auto_ptr<A>
// 2. мы его потеряли
// 3. он деструктировался, освобождая память
}
Читать по теме: Евангелие от Саттера (Exceptional C++), Item 37.
Здравствуйте, Аноним, Вы писали:
А>Плохо ли выделить в функции память для некоторой динамической переменной, а затем вернуть ссылку на неё? А>Когда в таком случае будет освобождена (или как можно будет освободить) память из под неё?
Вообще-то этот прием много где используется, например в strdup и других функциях стандартной библиотеки
Re[2]: ссылка на динамическую переменную
От:
Аноним
Дата:
18.10.04 07:04
Оценка:
Здравствуйте, Анна Савельева, Вы писали:
АС>Вообще-то этот прием много где используется, например в strdup и других функциях стандартной библиотеки
Испльзуется, да. Но лучше не использовать
char *_strdup( const char *strSource );
Ну тут обсуждали ссылку, то есть, (А&) а не указатель (A*). Тут западла не ждешь, однако ага! Вот оно!
И, во-вторых, даже возврат "сырого" указателя это плохо в С++.
Так как не понятно, чем его освобожадать.
delete[], delete, free, MyDeallocotor, LocalFree, CoTaskMemFree, SysFreeString.........
Юниксоиды тоже могут, наверное, неслабый список привести.
В С просто по другому нельзя, поэтому strdup — это для использования в С, в С++ ее лучше не применять.