0

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.

heretoinfinity
  • 1,528
  • 3
  • 14
  • 33

1 Answers1

1

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    You may also wish to mention options such as using a `std::vector` or some other standard container, since they can simplify the management of dynamically allocated arrays – Peter Apr 01 '20 at 01:29
  • Thanks. That was dumb of me. Why would the compiler mention `rvalue`? Is it referring to the type, `unsigned int` or `[d_width * d_height]`? – heretoinfinity Apr 01 '20 at 01:30
  • 1
    @heretoinfinity - The rvalue mentioned is the result of the `new` expression. The compiler is telling you, possibly in a overly complicated but technically correct way, that the result of a `new` expression (a pointer `unsigned int *`) cannot be stored in an `unsigned int`. – Peter Apr 01 '20 at 01:32
  • @Peter, thanks. I should have mentioned that the existing implementation uses arrays. I was just playing with the code trying to understand how to put together `operator=` on my own to make sure I understand it and started with this fiddling to understand initialization list. I would have opted for `std::vector` if I had been designing this from scratch myself. – heretoinfinity Apr 01 '20 at 01:32