0

I am working on a program that needs to write raw image data to a memory buffer. Currently my implementation looks like this:

std::unique_ptr<unsigned char[]> _Screen;
...
_Screen.reset(new unsigned char[width * height * 3]);
std::fill(_Screen.get(), _Screen.get() + (width * height), 0);
...
_Screen[(j * _ScreenWidth + i) * 3] = red;
_Screen[(j * _ScreenWidth + i) * 3 + 1] = green;
_Screen[(j * _ScreenWidth + i) * 3 + 2] = blue;

I would really like to use some STL containers here if possible. I don't know the size of the screen until runtime, so std::array is out. It should be possible to redefine screen using a std::vector<unsigned char> as follows:

std::vector<unsigned char> _Screen
...
_Screen.resize(width * height * 3);

But I am wondering if the element access will be any slower than using the C-style array? (I am assuming the reallocation will be slower but that is OK for this application).

I was also wondering if it would make more sense to do something like the following:

struct Pixel
{
    unsigned char red;
    unsigned char green;
    unsigned char blue;
};
...
std::vector<Pixel> _Screen;
...
_Screen.resize(width * height);
...
_Screen[(j * _ScreenWidth + i)].red = red;
_Screen[(j * _ScreenWidth + i)].green = green;
_Screen[(j * _ScreenWidth + i)].blue = blue;    

But I am going to need to convert to a single array of unsigned char eventually so while this represents the data better during my computation, I'm not sure how hard that would be. Will using the struct approach be any slower and is it safe to convert to the unsigned char later using something like:

unsigned char *screen = reinterpret_cast<unsigned char *>(_Screen.data());
Cœur
  • 37,241
  • 25
  • 195
  • 267
Max Ehrlich
  • 2,479
  • 1
  • 32
  • 44
  • 2
    Names like `_Screen` that begin with an underscore followed by an uppercase letter are reserved to the implementation. – imreal Jul 23 '14 at 00:29
  • @imreal Thanks for your concern but this wasn't really a style question. The convention we use is pascal casing with private member variables using a leading _ – Max Ehrlich Jul 23 '14 at 00:45
  • 1
    As I mentioned on a comment on the answer below: "You WILL lose performance with the vector. In C++, all elements of the vector are set to 0/default/NULL upon resize/allocation. For a regular array, this is NOT the case." – Brandon Jul 23 '14 at 02:39
  • @Brandon This is what I figured and it's actually fine for this application, you can see that I'm zeroing the original array anyway with std::fill (e.g. to start with an all black screen) – Max Ehrlich Jul 23 '14 at 12:20
  • @imreal Would you mind pointing me to the spec that reserves those names? I'd like to read it over – Max Ehrlich Jul 23 '14 at 12:21
  • 1
    @MaxEhrlich of course, from the Standard: 17.6.4.3.2 Global names [global.names] 1 Certain sets of names and function signatures are always reserved to the implementation: — Each name that contains a double underscore _ _ or begins with an underscore followed by an uppercase letter (2.12) is reserved to the implementation for any use. — Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace. – imreal Jul 23 '14 at 20:11
  • @imreal Thanks for citing that, I read it over (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf) as well, it seems like that only refers to the global namespace, while I am using it here as a member variable, but I might be interpreting it wrong. – Max Ehrlich Jul 24 '14 at 13:42
  • 1
    @MaxEhrlich Section 17.6.4.3.2 Global Names has 2 bullets, the second one: "Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace. " refers to the global namespace as you say, but the first one "Each name that contains a double underscore _ _ or begins with an underscore followed by an uppercase letter (2.12) is reserved to the implementation for any use." reserves names for ANY USE. Please reread that. – imreal Jul 24 '14 at 18:59
  • 1
    @MaxEhrlich This can help http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier – imreal Jul 24 '14 at 19:07

1 Answers1

1

std::vector is basically a C style array already, it just manages the allocation of the block. If you initialize the size of the vector then it allocates the size once, and then you can just access the internal array buffer and mess with the data directly if you want, or you can use the overloaded bracket operators. In the end though, I don't believe you will lose any noticeable performance with doing this. It is up to what looks good to you.

As for your second question, you probably are better off sticking to the first iteration just to avoid complications. However, if your Pixel struct is simply three unsigned chars, memory-wise it is in the same format as an array of 3 uchar's already, so there is little difference, you could still just iterate through the entire memory block char by char and put it back into the image, and vica-versa.

Lochemage
  • 3,974
  • 11
  • 11
  • Thanks this is what I was thinking but I wanted to see what other people thought before going with it, I will likely use the vector implementation – Max Ehrlich Jul 23 '14 at 00:44
  • 1
    You WILL lose performance with the vector. In C++, all elements of the vector are set to 0/default/NULL upon resize/allocation. For a regular array, this is NOT the case. – Brandon Jul 23 '14 at 02:34
  • 1
    However, since the vector is only resized once, it really doesn't account for enough performance loss to make any difference in the end. – Lochemage Jul 23 '14 at 03:11