C ++ два объекта, содержащие указатели на разные части одного массива - PullRequest
0 голосов
/ 10 января 2020

Я пытаюсь создать два класса, Volume и Slice, и создать метод в Volume, чтобы он мог вернуть часть своих данных в виде объекта Slice. Я хочу, чтобы два объекта совместно использовали память, чтобы изменить любой из них изменит те же данные. В настоящее время у меня есть:

#include <complex>
using namespace std;


class Slice{
public:
    Slice(unsigned long Nx,unsigned long Ny){   //Contructor
        nx = Nx;
        ny = Ny;
        data = new complex<double>[Nx*Ny];
    }

    Slice(unsigned long Nx,unsigned long Ny,complex<double>* inputDataPtr){ //Contructor
        nx = Nx;
        ny = Ny;
        data = inputDataPtr;
    }

    Slice(const Slice&  inputObj){ // Copy contructor
        nx = inputObj.nx;
        ny = inputObj.ny;
        data = inputObj.data;
    }

    ~Slice(){ //destructor
        delete data;
    }
private:
    // DATA:
    unsigned long     nx;
    unsigned long     ny;
    complex<double>*  data;
};

class Volume{
public:
    Volume(unsigned long Nx,unsigned long Ny,unsigned long Nz){ //Contructor
        nx = Nx;
        ny = Ny;
        nz = Nz;
        data = new complex<double>[Nx*Ny*Nz];
    }

    ~Volume(){ //destructor
        delete data;
    }

    const Slice& get_slice(unsigned long zindex){
            return Slice(nx,ny, &(data[zindex*nx*ny]));
    }
private:
    // DATA:
    unsigned long     nx;
    unsigned long     ny;
    unsigned long     nz;
    complex<double>*  data;
};



int main(){
    unsigned long Nx = 1;
    unsigned long Ny = 2;
    unsigned long Nz = 3;

    Volume testVolume(Nx,Ny,Nz);
    /* initialise data in testVolume */
    Slice slice = testVolume.get_slice(1);

    return 0;
}

Мне также нужно иметь возможность создавать отдельные слайсы, которые не связаны с объемом, поэтому класс слайсов должен также выделять свой собственный указатель.

Когда я запускаю это, он говорит, что *** free (): неверный указатель: 0x0000000000ff1180 ***

Я думаю, проблема в том, что когда я вызываю метод get_slice из testVolume, код уничтожает временный объект слайса. в ответ он пытается освободить несуществующий указатель и вызвать проблемы.

Как мне избежать этого? После небольшого поиска мне, вероятно, нужен умный указатель shared_ptr? Как мне это включить?

Спасибо.

Ответы [ 3 ]

0 голосов
/ 10 января 2020
#include <iostream>
#include <memory>
#include <complex>

class Slice{
public:
    Slice(unsigned long Nx, unsigned long Ny) :
        nx(Nx),
        ny(Ny),
        data(std::make_shared<std::complex<double>[]>(Nx*Ny))
    {}

    Slice(unsigned long Nx, unsigned long Ny, std::shared_ptr<std::complex<double>[]> data) :
        nx(Nx),
        ny(Ny),
        data(data)
    {}

private:
    unsigned long     nx;
    unsigned long     ny;
    std::shared_ptr<std::complex<double>[]> data;
};

class Volume{
public:
    Volume(unsigned long Nx, unsigned long Ny, unsigned long Nz) :
        nx(Nx),
        ny(Ny),
        nz(Nz),
        data(std::make_shared<std::complex<double>[]>(Nx * Ny * Nz))
    {
    }

    Slice get_slice(unsigned long zindex)
    {
        // Use std::shared_ptr aliasing constructor
        return Slice(nx, ny,
                     std::shared_ptr<std::complex<double>[]>(data, &data[zindex * nx * ny]));
    }
private:
    // DATA:
    unsigned long     nx;
    unsigned long     ny;
    unsigned long     nz;
    std::shared_ptr<std::complex<double>[]> data;
};



int main(){
    unsigned long Nx = 1;
    unsigned long Ny = 2;
    unsigned long Nz = 3;

    Volume testVolume(Nx,Ny,Nz);
    /* initialise data in testVolume */
    Slice slice = testVolume.get_slice(1);
}

Демо

0 голосов
/ 10 января 2020

Ваша проблема возникает здесь:

   Slice(unsigned long Nx,unsigned long Ny,complex<double>* inputDataPtr){ //Contructor
        nx = Nx;
        ny = Ny;
        // this is a shallow copy
        data = inputDataPtr;
    }

Теперь, когда вы удаляете его здесь, вы фактически удаляете тот в Томе

 ~Slice(){ //destructor
        delete data;
    }

Когда вызывается деструктор Тома, вы пытаетесь удалите его снова:

  ~Volume(){ //destructor
        delete data;
    }

, что приводит к ошибке. Чтобы исправить это, просто не удаляйте его в деструкторе Slice.

Вам также следует изменить эту функцию:

const Slice& get_slice(unsigned long zindex){
            return Slice(nx,ny, &(data[zindex*nx*ny]));
    }

В настоящее время вы возвращаете ссылку на локальный объект, который будет уничтожен в тот момент, когда вы вернетесь. Чтобы это исправить, вы должны рассмотреть использование raw или shared_ptr.

0 голосов
/ 10 января 2020

Для начала эта функция

const Slice& get_slice(unsigned long zindex){
        return Slice(nx,ny, &(data[zindex*nx*ny]));
}

имеет неопределенное поведение, поскольку возвращает ссылку на локальный объект типа Slice, который будет удален после выхода из функции.

Во-вторых этот конструктор

Slice(unsigned long Nx,unsigned long Ny,complex<double>* inputDataPtr){ //Contructor
    nx = Nx;
    ny = Ny;
    data = inputDataPtr;
}

не создает динамически данные, на которые указывает элемент данных data. Поэтому вызов деструктора

~Slice(){ //destructor
    delete data;
}

объекта, созданного таким образом, может привести к неопределенному поведению.

Аналогичная проблема существует с конструктором копирования

Slice(const Slice&  inputObj){ // Copy contructor
    nx = inputObj.nx;
    ny = inputObj.ny;
    data = inputObj.data;
}

Деструктор может попытаться удалить одну и ту же память два раза.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...