Search code examples
c++new-operatorrvaluelvalueinitialization-list

Can I get memory on a heap for an array in an initialization list from prior mentioned instance variables?


I am trying to allocate memory on the heap for an array at object creation in my custom constructor. The array's size is determined by previously initialized instance variables. Here's my code for clarity.

struct PNG {

    PNG() = delete;
    PNG(unsigned width, unsigned height):
        d_width(width),
        d_height(height),
        d_imageData(new unsigned int [d_width * d_height])
    {
    };

    PNG(PNG const &);

    PNG & operator = (PNG & other);

    friend std::ostream & operator << (std::ostream & os, PNG & png);

    unsigned d_width;
    unsigned d_height;
    unsigned d_imageData; // unsigned d_imageData []; has the same issue
};

This code gives me the error:

error: cannot initialize a member subobject of type 'unsigned int' with an rvalue of
      type 'unsigned int *'
        d_imageData(new unsigned int [d_width * d_height])

I am confused by two things:

  1. the way I see it, the array would be requesting memory and so would be a container, hence an lvalue and not an rvalue which wouldn't have storage.
  2. Are the variables d_width, d_height accessible after their own mention in the initialization list?

I had seen it done this way but wanted to try the initialization list. Now, I am learning something new by playing with the code. Is this the only way that is possible?

PNG(unsigned int width, unsigned int height) {
    width_ = width;
    height_ = height;
    imageData_ = new HSLAPixel[width * height];
  }

This question comes close but it uses std::initializer_list which I am not trying to use and I am not going to need templates as suggested in the accepted answer. More importantly, the array values would be filled out later and not at object construction.


Solution

  • Your constructor is fine. But since you are allocating memory for d_imageData using new[], you need to declare d_imageData as a pointer type, not an integer type, eg:

    unsigned int *d_imageData; // <-- notice the *
    

    (and don't forget to include a destructor that calls delete[] d_imageData; - see the Rule of 3/5/0).

    And yes, you can use d_width and d_height in the call to new[] in your constructor's member initializer list, since they are declared before d_imageData in of the declaration of PNG, and thus are initialized before d_imageData.