[C++] STL и память
{
public:
int Value1;
int Value2;
std::map<int, int> Links1;
std::map<int, int> Links2;
};
class Tree
{
private:
std::vector<Node*> _nodes; //дерево, выложенное в линию
}
class Algorithm
{
private:
Tree* _parameters; //указатель на динамический массив параметров
}
И вот в классе Algorithm мне нужно периодически удалять все объекты Tree и все, что они содержат.
(STL-вские контейнеры были выбраны в связи с частым изменением параметров. А то, что дерево выложено в струнку - это просто исторически сложилось.)
Во интернетах пишу, что контейнеры просто так не очистишь, и память они сами не освободят. Я даже писал:
{
public:
~Tree()
{
for (std::vector<Node*>::iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
delete *iter;
}
}
Но что писать в деструктуре Node, я уже не представляю.
А память утекает оооочень стремительно... Как быть?
delete *iter;
можно использовать умные указатели http://www.rsdn.ru/article/cpp/smartptr.xml.
Пример использования:
В результате все объекты Node при очистке вектора удалаться сами.
Я так понял, речь идёт о резервировании пямяти контейнером _nodes. Чтобы принудительно сбросить резерв, можно воспользоваться трюком:
Какая интересная штука. Никогда раньше не встречал. Спасибо! Завтра попробую.
Но в статье не описана производительность таких указателей. На опыте личном не ощущали разницу во времени работы?
можно использовать умные указатели
Только не std::auto_ptr ни в коем случае в данном примере.
Статья про УУ, приведённая выше раскрывает эту проблему:
Шаблон auto_ptr обеспечивает владение экземпляром объекта и его корректную очистку при выходе из области видимости – иными словами, реализует принцип RAII. Тем не менее, следует принимать во внимание необычную семантику копирования и присваивания – разрушающее копирование. В частности, эта семантика не позволяет использовать auto_ptr в контейнерах стандартной библиотеки.
Выходом из этой ситуации является реализация умного указателя с подсчётом ссылок – shared_ptr.
Да но очень вскользь. )
Все таки STL на первый взгляд и ни причем. Пытаюсь использовать crtdbg для утечек... Утечек показывает много, а вот найти их пока не удается. Причем проблема кроется гораздо глубже, чем в описанном выше коде. Эхх..
А утечка памяти может возникать без явного использования оператора new(malloc)?
А утечка памяти может возникать без явного использования оператора new(malloc)?
Это как учитывая, что у тебя там указатели, которым ты делаешь delete? =)
Немножко не понял вопроса.... Там - это в коде, указанном в топике?) Про него можно забыть, проблема глубже. Я же не писал функций, которые обрабатывают и вычисляют всю ту байду. Вот там и есть утечки. Например, есть метод который... А, к черту слова. Код:
Здесь голова всего, нужно получить вероятность из структуры в зависимости от параметра newHistory, а также выписать некоторый кусок входного параметра в maxSubHistory;
FullHistory* maxSubHistory;
_CrtMemState ms;
_CrtMemCheckpoint(&ms);
Nullable<double> modelProbability = _modelContainer->GetProbability(newHistory, &maxSubHistory);
_CrtMemDumpAllObjectsSince(&ms);
Обертка структуры:
{
std::wstring maxLetterSubHistory;
Nullable<double> probability =
_ngramContainer->GetProbability(inputHistory->GetConstString(), maxLetterSubHistory);
*maxSubHistory = new FullHistory(maxLetterSubHistory);
return probability;
}
Та самая жесткая функция, ради которой всё:
{
std::list<wchar_t> maxSubHistory;
int length = inputString.size();
unsigned int oldShift = 0;
unsigned int newShift;
for ( int i = length - 1; i >= 0; i-- )
{
unsigned int currentLetterCode = (unsigned int) _alphabet->EncodeLetter(inputString);
newShift = _links[oldShift + currentLetterCode];
if ( newShift == 0 )
break;
maxSubHistory.push_front(inputString);
oldShift = newShift;
}
if (maxSubHistory.size() == 0)
outputString = inputString[length - 1];
else
outputString = std::wstring(maxSubHistory.begin(), maxSubHistory.end());
oldShift = 0;
newShift = 0;
unsigned int currentLetter;
for ( int i = length - 2; i >= 0; i-- )
{
currentLetter = (unsigned int) _alphabet->EncodeLetter(inputString);
newShift = _links[oldShift + currentLetter];
if ( newShift == 0 )
{
currentLetter = (unsigned int) _alphabet->EncodeLetter(inputString[length - 1]);
return _values[oldShift + currentLetter];
}
oldShift = newShift;
}
currentLetter = (unsigned int) _alphabet->EncodeLetter(inputString[length - 1]);
return _values[newShift + currentLetter];
}
И пояснения, что собой представляют структуры:
{
public:
std::vector<WordIdDictionary> WordHistory;
std::wstring LetterHistory;
}
class WordIdDictionary
{
public:
unsigned int WordId;
std::wstring* Dictionary;
}
template<class T> class Nullable
{
private:
T _value;
bool _hasValue;
}
//К слову, от STL я инкуда не ушел, поэтому топик даже остается пока актульным :D
Так вот, за весь стек вызовов я делаю всего ОДИН new. Но crtdbg-отчет утверждает, что у меня аж 6 блоков памяти вытекло в никуда.
{61891} normal block at 0x074AD208, 8 bytes long.
Data: < 3I > 20 33 49 07 00 00 00 00
{61890} normal block at 0x074AD1D0, 8 bytes long.
Data: <43I > 34 33 49 07 00 00 00 00
{61887} normal block at 0x07493320, 52 bytes long.
Data: < J > 08 D2 4A 07 00 00 00 00 00 00 00 00 00 00 00 00
{61881} normal block at 0x074AD010, 8 bytes long.
Data: < 3I > 94 33 49 07 00 00 00 00
{61880} normal block at 0x074ACFD8, 8 bytes long.
Data: < 3I > 80 33 49 07 00 00 00 00
{61879} normal block at 0x07493380, 52 bytes long.
Data: < J > D8 CF 4A 07 00 00 00 00 00 00 00 00 00 00 00 00
Object dump complete.
Откуда они вообще взялись?
[COLOR="red"]UPD: Правда, в логе не было фразы "Detected memory leaks!". Нужно было другую функцию использовать для отловли утечек(_CrtDumpMemoryLeaks())?[/COLOR]
_alphabet->EncodeLetter возвращает из std::map<wchar_t, unsigned char> некий (собственноручно созданный)код символа и выглядит так:
{
std::map<...>::iterator = _codedDictionary.find(letter);
if (iterator == _codedDictionary.end())
throw "error";
return iterator->second;
}
Но вообще можете не разбираться. Ответ на свои вопросы я так и не нашел, а просто пошел другим способом.
Я нашел места, где зачем то делал "new". Делал я это для того, чтобы в функции передавать без копирования в памяти. Почему я сразу не использовал создание элемента в стеке, а не в куче, и почему я не пользовался передачей параметров по ссылке, я не знаю. Но когда я перестал писать new и стал пользоваться ссылками, то утечки прекратились. И STL тут оказался совсем ни причем.