4

I need a data structure in C++ that acts like a standard container of bytes but aligns the buffer at a multiple of four bytes. I'd like to re-use standard library abstractions as much as possible, rather than rolling my own abstraction.

Until now, I had been using std::string and std::vector<std::uint8_t> for this purpose. Unfortunately, I've gotten bug reports on the latest Mac OS, where apparently string::data() is no longer 4-byte aligned, but rather rather at an address congruent to 1 mod 4. As soon as I saw this, I realized of course nothing in the spec guarantees strings will be 4-byte aligned. I could switch over to vector<char>, but unfortunately now I'm not sure why this should be 4-byte aligned. Potentially even with a custom allocator the vector implementation could do something strange at the beginning of the buffer it allocates.

My question: What is a simple way of getting a dynamically-sized container of single-byte objects from the C++ standard library in which the first byte is at a 4-byte aligned address and individual bytes can be accessed through operator[]?

Note that this is not the same thing as asking how to ensure that the allocator used by the container returns 4-byte aligned memory. For example, std::string still allocates 4-byte aligned memory (probably 8, actually), it's just that on Mac OS string::data() does not point to the start of the allocated buffer. I don't see anything in the spec that would prevent a vector<char> from doing the same thing, even though for now that seems to work.

user3188445
  • 4,062
  • 16
  • 26
  • 1
    Not the simplest to implement, but the simplest to allow reusing the standard library, is to write a custom allocator. – StoryTeller - Unslander Monica Feb 08 '18 at 19:45
  • Write your own allocator that gets an aligned address? – NathanOliver Feb 08 '18 at 19:47
  • 4
    Possible duplicate of [Making std::vector allocate aligned memory](https://stackoverflow.com/questions/12942548/making-stdvector-allocate-aligned-memory) – llllllllll Feb 08 '18 at 19:47
  • @liliscent though subject of that question looks duplicate, author restrict it to custom allocator there. I do not think this is a duplicate as custom allocator is not the only solution here. – Slava Feb 08 '18 at 20:04
  • @NathanOliver What basis do you have for arguing that the custom allocator will work? Couldn't a `vector` implementation allocate memory but skip the first element (which would be one byte in the case of `char`s)? – user3188445 Feb 08 '18 at 21:28
  • @user3188445 AFAIK it has to use the first element otherwise `data` wouldn't work. – NathanOliver Feb 08 '18 at 22:07
  • @NathanOliver sadly that argument doesn't work, or else you could argue that std::string has to use the first byte of its allocation, which it doesn't. `data()` just has to return the first element in the array, which might be the first thing returned by the allocator or not. – user3188445 Feb 09 '18 at 23:58

1 Answers1

1

One of the solution is to use std::vector<uint32_t> internally, encapsulate that and convert data() to unsigned char * when you use it.

Slava
  • 43,454
  • 1
  • 47
  • 90
  • That doesn't work, unfortunately, because I need byte indexed access. So at that point I might as well just implement my own container. – user3188445 Feb 08 '18 at 21:29
  • @user3188445 that does work indeed, as I said convert pointer, returned by `data()` to `unsigned char *` and you have byte indexed access. – Slava Feb 08 '18 at 21:36
  • But if I'm using `std::vector`, I'm using `std::vector::operator[]`--I can't replace that with something that converts pointers. Also, `value_type`, etc. will all be wrong. I would basically need to implement my own container that internally contains a `std::vector`, at which point I might as well just implement my own container in terms of `malloc`. – user3188445 Feb 11 '18 at 07:55
  • Yes you definitely can write your own container, but I am not sure if writing it properly would be simpler than a thin wrapper over `std::vector`. I gave you one of the solutions, it is up to you to decide which one to use. – Slava Feb 11 '18 at 18:16