#ifndef __VECTOR_H__
#define __VECTOR_H__
#include "types.h"
#include "memman.h"
/// matrices w x h
class linear
{
public:
array2* m;
/// by default creating zero matrix h0 x w0
linear(uint w0, uint h0);
~linear();
/// multiply matrix by double number
linear muln(double n);
/**
"+" - add matrices;
"-" - substract matrices;
"*" - multiply matrices;
*/
linear operator + (linear mat);
linear operator - (linear mat);
linear operator * (linear mat);
/**
"~" - transpose matrix
*/
linear operator ~ ();
/**
find a determinant of matrix, if it's square matrix;
return 0, if matrix is not square
*/
double det();
/**
invert square matrix;
return maxtrix of 0 x 0 size, if matrix is not square
*/
linear invert();
};
typedef class linear* plinear;
#endif
#include "mvector.h"
#include "memman.h"
#include <math.h>
#include <stdio.h>
/// finding determinant of square array n x n
double Det(array2* ar, uint n)
{
if (n == 0)
return 0;
if (n == 1)
{
return ar->m[0][0];
}
int p, i, j;
int a, b, d;
double c=0;
p = 1;
ar->link();
array2 *na = mem_alloc(n-1, n-1);
for (i = 0; i < n; i++)
{
a = 0;
b = 0;
for (a = 1; a < n; a++)
{
d = 0;
for (b = 0; b < n; b++)
{
if (b == i)
continue;
na->m[a-1][d] = ar->m[a][b];
d++;
}
}
c += p*Det(na, n-1)*(ar->m[0][i]);
p = -p;
}
na->unlink();
ar->unlink();
return c;
}
linear::linear(uint w0, uint h0)
{
m = mem_alloc(w0, h0);
}
linear::~linear()
{
if (m != NULL)
m->unlink();
}
linear linear::operator + (linear mat)
{
mat.m->link();
if (m->w != mat.m->w || m->h != mat.m->h)
{
mat.m->unlink();
// error
linear bad(0,0);
return bad;
}
linear res(m->w, m->h);
uint i, j;
for (i = 0; i < m->h; i++)
for (j = 0; j < m->w; j++)
{
res.m->m[i][j] = m->m[i][j] + mat.m->m[i][j];
}
mat.m->unlink();
res.m->link();
return res;
}
linear linear::operator - (linear mat)
{
mat.m->link();
if (m->w != mat.m->w || m->h != mat.m->h)
{
mat.m->unlink();
// error
linear bad(0,0);
return bad;
}
linear res(m->w, m->h);
uint i, j;
for (i = 0; i < m->h; i++)
for (j = 0; j < m->w; j++)
{
res.m->m[i][j] = m->m[i][j] - mat.m->m[i][j];
}
mat.m->unlink();
res.m->link();
return res;
}
linear linear::operator * (linear mat)
{
mat.m->link();
if (m->w != mat.m->h)
{
mat.m->unlink();
// error
linear bad(0,0);
return bad;
}
uint i, j, k, w1, h1, l;
w1 = mat.m->w;
h1 = m->h;
l = m->w;
linear res(w1, h1);
for (i = 0; i < h1; i++)
for (j = 0; j < w1; j++)
{
res.m->m[i][j] = 0;
for (k = 0; k < l; k++)
res.m->m[i][j] += m->m[i][k] * mat.m->m[k][j];
}
mat.m->unlink();
res.m->link();
return res;
}
linear linear::muln(double n)
{
linear res(m->w, m->h);
uint i, j;
for (i = 0; i < m->h; i++)
for (j = 0; j < m->w; j++)
res.m->m[i][j] = m->m[i][j]*n;
res.m->link();
return res;
}
linear linear::operator ~ ()
{
linear res(m->h, m->w);
uint i, j;
for (i = 0; i < m->h; i++)
for (j = 0; j < m->w; j++)
res.m->m[j][i] = m->m[i][j];
res.m->link();
return res;
}
linear linear::invert()
{
if (m->w != m->h)
{
linear bad(0,0);
return bad;
}
int i, j, a, b, c, d;
int w = m->w;
int h = m->h;
linear res(w, w);
array2* nm = mem_alloc(w-1, w-1);
double dd = Det(m, w);
for (i = 0; i < w; i++)
for (j = 0; j < w; j++)
{
a = 0;
b = 0;
c = 0;
d = 0;
for (a = 0; a < w; a++)
{
if (a == i)
continue;
d = 0;
for (b = 0; b < w; b++)
{
if (b == j)
continue;
nm->m[c][d] = m->m[a][b];
d++;
}
c++;
}
res.m->m[j][i] = Det(nm, w-1)/dd; // transpose i and j
}
nm->unlink();
res.m->link();
return res;
}
double linear::det()
{
int w = m->w;
int h = m->h;
if (w != h)
{
//error
return 0;
}
double d = Det(m,w);
return d;
}
Как люди умудряются допускать утечки памяти? Ведь удобный менеджер памяти, следящий за выделением и освобождением памяти пишется за пару часов?
-- как приведенный кусок кода соотноситься с реальными приложениями, в которых бывают таки утечки? Реальные приложения - это часто много-много потоков, минимум тысяч десять строк кода, а не пример из учебника на пару экранов.
Вы пробовали ваш менеджер памяти использовать в проекте побольше?
То, что я пишу - вполне себе нужное приложение, за которое мне готовы платить.
Это достаточно условие реальности?
Уточню: те здоровые приложения на много десятков тысяч строк кода, в которых реально бывают утечки.
И чем таки плох std/boost::shared_ptr ? При грамотном использовании shard_ptr/weak_ptr, оно позволяет в разы снизить головную боль в плане утечек памяти, и никакой велосипед изобретать не надо. («почему тогда все равно течет?» - то, что написано без shared_ptr разом на использование shared_ptr не перенести и не всегда применимо, да и сам по себе, shared_ptr, без аккуратного использования мозга - все равно не панацея, но если с нуля использовать мозг + shared_ptr, то вероятность утечек можно свести почти к нулю).
В C++ с его системой ООП утечки могут случаться на казалось бы пустом месте.
Пример можно?
Во-первых тянет boost, а объяснять, что я тяну здоровенную библиотеку только для контроля утечек памяти, я не особо хочу.
Даже до C++11 был std::tr1::shared_ptr, но даже если и тянуть буст - с ним же линковаться не надо. Оно только *.hpp потребует включить, весь код - шаблонами (почти, shared_ptr - точно), так что ничего лишнего не подключиться.
Вопросом утечек памяти занялся недавно относительно
Что-то ни разу в треде не было упомянуто заветное слово Valgrind, однако.
Если не придерживаться 100% smart-pointers и контроля доступа в runtime, то альтернатив Valgrind вроде бы как и нету.
Я про то, что boost — набор очень хорошо разделенных компонент, большая часть которых никакой отдельной сборки вообще не требует, все в заголовочных файлах. Для некоторых вещей (асинхронный ввод-вывод, инструменты для многопоточности) реализация, все-таки, лежит отдельно, но можно просто перенести в свой проект несколько .cpp файлов.
НъТъ. В некоторых случаях хочется явно сказать «а-ну выкинули все, что в этом пуле» и получить немедленное освобождение всяческих ресурсов (открытых соединений, файлов и тд). А не дожидаться, пока ленивый gc дочухает, что $ресурс уже можно освобождать.
GC вроде как не занимается освобождением неуправляемых ресурсов.
GC вроде как не занимается освобождением неуправляемых ресурсов.
В жабе, де факто, занимается. Если GC занимается *только* памятью, то он тогда становится ограничен, приходится писать свой учет неуправляемых ресурсов. А если у тебя в программе есть свой учет ресурсов, нафига тебе GC?
Я что-то не пойму о чем ты. GC, конечно, очищает память с неуправляемыми ресурсами, но перед этим ты обязан ручками закрыть файлы и пр. В C#, к примеру есть инструкция using для этого:
using(var obj = new SomeDisposableObject())
{
...
}
Все содержимое блока будет обернуто в try-catch и по выходе из блока будет вызван метод Dispose объекта в котором должен быть код очистки неуправляемых ресурсов. В последней жабе, ЕМНИП, тоже появилась подобная конструкция. Однако код в Dispose придется все равно писать ручками.
В последней жабе, ЕМНИП, тоже появилась подобная конструкция. Однако код в Dispose придется все равно писать ручками.
Согласен на 100%, жаба, как ни парадоксально сначала кажеться, куда более предрасположена к утечка ресурсов вроде хендлов файлов или сокетов, C++ в этом плане куда удобнее, а после плюсов - того и гляди, забудешь какой-нибудь flush или close, и все к чертям в Java летит :)
Ведь удобный менеджер памяти, следящий за выделением и освобождением памяти пишется за пару часов?
overhead очень высокий. Встречаются случаи, когда программа, будучи переписана на C/C++ (частично конечно), начинала работать на порядок быстрее, чем всякие ваши python'ы. Просто за счёт того, что нет никаких проверок и сборок мусора. Расход памяти тоже меньше.
Если у меня будет много потоков, то для этого дела я напишу другой менеджер, который будет учитывать и многопоточность.
в чём проблема? для каждого класса ты можешь определить своё new и delete, вот тебе и менеджер. Внутри него можешь организовать просто что угодно, хоть как в жабе, хоть как в пайтоне, а хочешь - как в пхп. Не должна delete освобождать память? Пожалуйста!
Менеджер памяти спасёт максимум от забытого free. А если брать даже тот же C#, то несмотря на всю его управляемость, память там можно заставить течь очень даже. А уж если COM начать использовать, то вообще трэш, угар и содомия.
Объекты должны оставаться на своем месте. И удаляться там где созданы.
Это возможно только разве что копированием целого объекта при передаче в другую часть программы, но это плохо. В общем случае проследить за объектом вручную просто нельзя.