c ++ удалить ссылку - PullRequest
       4

c ++ удалить ссылку

4 голосов
/ 12 декабря 2010

Я все еще изучаю c ++ и у меня есть вопрос, который может быть очевиден, или, может быть, я просто не знаю, что я пытаюсь сделать. У меня есть функции, которые берут матрицу (класс, который я написал, у которого есть должным образом написанный деструктор) и создают из него новую матрицу, возвращая ссылку на новую. Мне нужно повторять, возможно, десятки тысяч раз на этих матрицах, поэтому я должен убедиться, что у меня нет утечек памяти. Итак, вопрос в том, как правильно удалить матрицу, которая мне больше не нужна, чтобы освободить место для следующей? Вот код, который я пытаюсь получить без утечек:

DynamicMatrix<double> x0 = getX0(n);

DynamicMatrix<double>exactU = getExactU(n);

DynamicMatrix<double> b = getB(n) * w;

DynamicMatrix<double> x1 = getX1(x0, b, w, n);

while( !isConverged(exactU,x1,e) ){
    delete x0; //<<<<< This doesn't work. Nor does delete &x0.
    x0 = x1;
    x1 = getX1(x0, b, w, n);
}

Каждый из методов getX () создает указатель на матрицу и возвращает ссылку на матрицу, как в getX0 ():

DynamicMatrix<double> &getX0(int n){
    DynamicMatrix<double>* mat1 = new DynamicMatrix<double>(n * n,1);
    for (int i = 1 ; i <= n; i++){
        for (int j = 1; j <= n; j++){
            mat1->set((i-1)*n +j, 1, 0);
        }
    }
    return *mat1;
}

Итак, вызов ошибки 'delete X0', потому что для этого нужен указатель. 'delete & X0' говорит, что освобожденный указатель не был выделен. Как правильно это сделать? Или я что-то не так делаю? При слишком больших матрицах и слишком большом количестве итераций на моем жестком диске large не хватает места, что я могу предположить только из-за большого количества утечек памяти.

Ответы [ 5 ]

6 голосов
/ 12 декабря 2010

Stroustrup R'lyeh Fhtagn .

Запись MyType myVar = MyFunction() создает новый объект, используя конструктор, который принимает тип возвращаемого значения myFunction в качестве аргумента.Все, что было возвращено myFunction, затем отбрасывается - в вашем примере getX0 возвращает ссылку на объект, который был выделен динамически, и, следовательно, утечка.

Серьезно, хотя - попробуйте создать матрицы в стеке (без new) и вернуть их как есть.Не должно вызывать особых проблем, так как в любом случае они, по-видимому, динамически распределяют свои данные внутри, и я подозреваю, что NRVO будет применять, чтобы избежать копирования (возвращенная матрица будет напрямую построена в соответствующем месте. x0x1 Волшебство внизу может быть реализовано следующим образом:

x0.swap(x1);
DynamicMatrix<double> temp = getX1(x0, b, w, n);
x1.swap(temp);

Поскольку операция подкачки может быть реализована в вашей динамической матрице в виде замены указателя (что очень быстро) вместо фактических данныхскопируйте, это должно быть очень быстро.

2 голосов
/ 12 декабря 2010

Вы должны использовать указатели.Оператор

DynamicMatrix<double> x0 = getX0(n);

Делает копию матрицы.Вы хотите

DynamicMatrix<double> *getX0(int n){
  DynamicMatrix<double>* mat1 = new DynamicMatrix<double>(n * n,1);
  ...
  return mat1;
}

Тогда

DynamicMatrix<double> *x0 = getX0(n);
...
delete x0;
1 голос
/ 12 декабря 2010

если getX() возвращает указатель, вы должны написать в первой строке:

DynamicMatrix<double>* x0 = getX0(n);

Это имело бы больше смысла, когда вы возвращаете новый указатель. Затем вы должны удалить его, как показано ниже.

Обратите внимание, что вы можете избежать многих проблем, используя boost::shared_ptr:

typedef boost::shared_ptr<DynamicMatrix<double> > dyn_matrix_ptr;

dyn_matrix_ptr x0 (getX0(n));
// use x0 as a normal pointer
...
// You don't have to manually delete it, it will be deleted automatically.
0 голосов
/ 12 декабря 2010

Правила для DynamicMatrix<double> в основном такие же, как и для int.

Если он был размещен в стеке как переменная 'auto', то правильный способ его очистки:ничего не делать - просто пусть он выпадает из поля зрения.Вы хотите, чтобы ваш код был максимально упорядочен таким образом, чтобы это имело место.

Если он был выделен с помощью «new», очистите его с помощью «delete».

Пожалуйста, наденьтеникогда не выделять что-то динамически, а затем возвращать это по ссылке.Вернуть указатель.На самом деле, не делайте этого, либо.Используйте умный указатель класса.Пожалуйста.

Пожалуйста, не динамически распределяйте вещи, если вам это не нужно.Просто сделайте локальное значение и верните его - по значению (это то, как вы справляетесь с тем фактом, что вы не можете вернуть ссылку на нестатическое локальное значение).Вы бы никогда, никогда, никогда не думали о написании кода, подобного следующему, верно?

int& give_me_a_value() {
    int* result = new int(rand());
    return *result;
}

Опять же: правила для DynamicMatrix<double> в основном такие же, как и для int.Вот почему вы реализуете конструкторы копирования, операторы присваивания и деструкторы: так что это на самом деле работает так, как вы ожидаете.

0 голосов
/ 12 декабря 2010

Ваша ошибка здесь:

DynamicMatrix<double> x0 = getX0(n);

Вам не обязательно использовать указатели. Вы можете вернуть ссылку на новый объект. Для удаления памяти просто возьмите адрес ссылки. Взяв адрес ссылки, вы получите адрес референта; Вы должны быть в состоянии позвонить

// receive newed memory in a reference
DynamicMatrix<double>& x0 = getX0(n);

// &x0 should give you the address of the allocated memory.
delete &x0;
...