开发者

"dynamic constructor" in c++

开发者 https://www.devze.com 2023-04-07 19:13 出处:网络
i am new to classes in C++ and i need to create a class \"Plot\" which has a method that reads in data from a file and creates a 3d grid.

i am new to classes in C++ and i need to create a class "Plot" which has a method that reads in data from a file and creates a 3d grid.

i understand that you can 开发者_JS百科make "default" constructors with default values or you can create a special constructor with predefined values.

in my "private" section, i have:

int nx; // number of "x" values
int ny; // number of "y" values
int nz; // number of "z" values
double* grid; // one dimensional array which stores nx*ny*nz values
double tgrid(int ix, int iy, int iz); // function which searches grid and returns value

now, i want to create my "plot" object and then AFTER that, dynamically create the "grid" array. is it possible to do this? or will i need to declare the size of the array "grid" when i first create "plot"?


Use std::vector grid; as your member. Then you can use grid.resize(nx*ny*nz) to force the size you want or use grid.push_back(value); for each value you want to add to the array.


It is possible:

class Plot{
   int nx; // number of "x" values
   int ny; // number of "y" values
   int nz; // number of "z" values
   double* grid; // one dimensional array which stores nx*ny*nz values
   double tgrid(int ix, int iy, int iz); // function which searches grid and returns value
public:
   Plot()
   {
      grid = NULL;
   }
   ~Plot()
   {
       delete[] grid;
   }
   void init(int x, int y, int z)
   {
      delete[] grid; //make sure no memory leaks since grid might have already been allocated
      nx = x;
      ny = y;
      nz = z;
      grid = new double[nx*ny*nz];
   }
};

After the construction, just call the method init:

Plot p();
p.init(2,3,4);

EDIT:

You should however consider Mark B's answer. I would also use something from std:: rather than a dynamically allocated array. Much easier to manage.

EDIT2:

As per Constantinius' answer, avoid init() methods when you can. If you specifically need the initalization AFTER construction, use it, otherwise keep all initialization logic in the constructor.


It depends on how your Plot class should be used. If you consider it necessary to create objects of this class only with valid sizes you should not allow a default constructor. You do this by defining your own constructor like that:

public:
Plot(int _nx, int _ny, int _nz) : nx(_nx), ny(_ny), nz(_nz) 
{
    // initialize your array
    grid = new double[nx*ny*nz];
}

also don't forget your destructor to clear the allocated memory:

~Plot() 
{
    delete[] grid;
}


class Plot {
    int nx; // number of "x" values
    int ny; // number of "y" values
    int nz; // number of "z" values
    double* grid; // one dimensional array which stores nx*ny*nz values
    double tgrid(int ix, int iy, int iz); // function which searches grid and returns value
public:
    /* default constructor */
    Plot() : nx(0), ny(0), nz(0), grid(NULL) { }
    /* rule of five copy constructor */
    Plot(const Plot& b) : nx(b.nx), ny(b.ny), nz(b.nz) {
        int max = nx*ny*nz;
        if (max) {
            grid = new double(max);
            for(int i=0; i<max; ++i)
                grid[i] = b.grid[i];
        } else
            grid = NULL;
    }
    /* rule of five move constructor */
    Plot(Plot&& b) : nx(b.nx), ny(b.ny), nz(b.nz) grid(b.grid) { b.grid = NULL; }
    /* load constructor */
    Plot(std::istream& b) : nx(0), ny(0), nz(0), grid(NULL) { Load(b); }
    /* rule of five destructor */
    ~Plot() { delete[] grid; }
    /* rule of five assignment operator */
    Plot& operator=(const Plot& b) {
        int max = b.nx*b.ny*b.nz;       
        double* t = new double[max];
        for(int i=0; i<max; ++i)
            t[i] = b.grid[i];            
        //all exceptions above this line, NOW we can alter members
        nx = b.nx;
        ny = b.ny;
        nz = b.nz;
        delete [] grid;
        grid = t;
    }
    /* rule of five move operator */
    Plot& operator=(Plot&& b) {   
        nx = b.nx;
        ny = b.ny;
        nz = b.nz;
        delete [] grid;
        grid = b.grid;
        b.grid = NULL;
    }
    /* always a good idea for rule of five objects */
    void swap(const Plot& b) {
        std::swap(nx, b.nx);
        std::swap(ny, b.ny);
        std::swap(nz, b.nz);
        std::swap(grid, b.grid);
    }

    /* your load member */
    void Load(std::istream& in) {
        //load data
        //all exceptions above this line, NOW we can alter members
        //alter members
    };
};

int main() {
     Plot x;  //default constructor allocates no memory
     Plot y(x); //allocates no memory, because x has no memory
     Plot z(std::cin); //loads from stream, allocates memory
     x = z; //x.grid is _now_ given a value besides NULL.
}

This answers your questions I think. Still: use a std::vector.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号