3

I am following a c++ course and there is something I would like to be able to do in one line. I have the following class:

class example {
private:
    int height, width;
    std::unique_ptr<uint8_t[]> pointer = nullptr;
public:
    example()
        :pointer(new uint8_t[height * width * 3]) // this works
    {}
};

But I would rather initialize the pointer member inline like:

unique_ptr<uint8_t[]> pointer = new uint8_t[height * width * 3]; // doesnt work

Is this possible?

Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
  • 1
    I strongly recommend against doing this. It makes you code brittle since `pointer` would now rely on the where `height` and `width` are defined in the class. If the class gets changed around to `std::unique_ptr pointer = ...; int height, width;` then you'll have undefined behavior. – NathanOliver Aug 27 '19 at 15:27
  • yea, but really dont take the class into consideration here, i wrote this quickly to be able to describe the problem, im making my code procedural now. and also im just learning for now to even make it work, i want to worry about best practises after i even understand the problem its self :). thanks. – CerribleToder Aug 27 '19 at 15:31
  • AFAIK `new` cannot be used in an initialization for a class-member declaration. If its somehow required, move the initialization to the constructor of the class (as you already show). – Ripi2 Aug 27 '19 at 15:41
  • 1
    @Ripi2 I think it can.`std::unique_ptr pointer{ new uint8_t[height * width * 3]() };` works fine. I think it has something to do with unique pointers of arrays `T[]` specialization. – Ron Aug 27 '19 at 15:45
  • @Ron now how on earth didnt i think of that, thanks for your help. – CerribleToder Aug 27 '19 at 15:48

2 Answers2

3

You can, this will work:

struct P {
    size_t height, width;
    std::unique_ptr<size_t[]> vals = std::make_unique<size_t[]>(height * width * 3);
};

Live example

But don't do this. Why?

If I do this:

struct P {
    size_t height;
    std::unique_ptr<size_t[]> vals = std::make_unique<size_t[]>(height * width * 3);
    size_t width;
};

I have undefined behaviour, because I will be using width uninitialized. At least if I do this:

struct P {
    P(size_t h, size_t w) :
       height{h}, width{w},
       vals{height * width * 3}
    {} // Initialization in the initialization list

    size_t height;
    std::vector<size_t> vals;
    size_t width;
};

Then a warning will appear stating out of order elements in the initializer list. And since I should be compiling with warnings as errors, I will, luckily, be unable to compile this buggy code. Finally, I am using a vector, which is definitely what you are looking for, it is much much nicer to use :)

Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
  • yeah im trying to make a bitmap, and looking at everyones code aside my course's instructor everyone seems to be using vectors. so i guess il just go with vectors. thanks for the help mate. – CerribleToder Aug 27 '19 at 15:42
  • std::unique_ptr is a good choice here. vector is unnecessary – Sopel Aug 27 '19 at 16:09
  • @CerribleToder C++ instructors have an annoying tendency to use C-style thinking in their course material. Sometime it's because they're trying to get a point across and sometimes it's because they're using material left over from when the course was based around C. The ones to watch out for are the instructors who think C++ is just C on steroids. If you suspect you have the third, supplement your education with additional [C++-specific reading materials](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – user4581301 Aug 27 '19 at 16:10
  • @sopel the `unique_ptr` can be a bit faster due to `vector` initializing its contents, but A) this is usually insignificant (profile to be sure) and B) the programmer picks up a few extra responsibilities, such as making sure copying is handled correctly. – user4581301 Aug 27 '19 at 16:15
  • im actually struggling to find c++ courses that cover real life projects, i guess books are the best way to do it. – CerribleToder Aug 27 '19 at 16:32
  • 1
    `vals{h * w * 3}` would be even better as now `vals` doesn't care where `height` and `width` are declared. – NathanOliver Aug 27 '19 at 16:34
0

The problem is unique pointer's operator= which is not defined for unique pointers holding arrays. Use the constructor instead:

unique_ptr<uint8_t[]> pointer {new uint8_t[height * width * 3]()};

or the std::make_unique function:

std::unique_ptr<uint8_t[]> pointer = std::make_unique<uint8_t[]>(height * width * 3);
Ron
  • 14,674
  • 4
  • 34
  • 47