3

What's the correct way to write the code below?

I have a memory manager which provides me with char *'s, but I need to work with arrays of uint32_t. How can I work around the strict aliasing rule? I understand that with a single object it's advised just to copy the contents with memcpy() but that solution is not acceptable for an array of objects.

char* ptr = manager()->Allocate(1000 * sizeof(uint32_));
uint32_t* u32ptr = reinterpret_cast<uint32_t*>(ptr);
....
u32ptr[x] = y;
4
  • 3
    Your manager should return a void*. It would fix all your problems (not including <insert joke>) Commented Sep 22, 2017 at 14:33
  • My early baldness problem was 10 years ago. Now it's just baldness. Commented Sep 22, 2017 at 14:36
  • I'm sorry, I didn't saw your profile pic before writing what was purely a joke. No offense taken? Commented Sep 22, 2017 at 14:37
  • Ha ha ha :) No offense taken :) Commented Sep 22, 2017 at 14:39

2 Answers 2

6

You can use placement-new:

uint32_t* u32ptr = new(ptr) uint32_t[1000];

Note that after this, the effective type of the storage is uint32_t, and you may not use ptr any more. You don't have to do anything special with the chars, because for types with a trivial destructor, you can end their lifetime simply by reusing the storage.

Sign up to request clarification or add additional context in comments.

10 Comments

Thanks! How can I know how many integers can be placed in the chunk of size X chars ? I am guessing dividing X by sizeof (uint32_t) is wrong..
The size of char is guaranteed to be 1 by the standard, so dividing by sizeof(uint32_t) is ok.
Yeah, I meant - alignment issues. say, ptr is is not aligned. I am guessing that placement new will align ints so some bytes won't be useful. I am asking whether there is a "standard" way to know number of items given the pointer and size.
Ah ok, now I understood. On x86 alignement is never an issue, for other cases there is a function that returns the maximum alignement, which I don't remember right now. (let me check...)
|
1

You could make the Manager class return std::unique_ptr<void, Manager::Deleter>( that is, with a unique pointer with a custom deleter). This makes the allocation use RAII to automagically deallocate when you go out of scope. And instead of using a pointer, prefer a gsl::span In that case, you could write:

constexpr const length = 1000;
auto allocated = manager()->Allocate(
    length * sizeof(std::uint32_t), 
    alignof(uint32_t) // supporting alignment here is important, otherwise
                      // you'll have to manually take care of that yourself
);
auto p = gsl::span<uint32_t>(new(allocated.get()) std::uint32_t[length], length);

Another alternative is to template the Manager class, or the allocation method, on an element type, and have it take care of things:

auto p = manager()->Allocate<std::uint32_t>(1000);

... and p will be an std::unique_ptr<uint32_t> to costructed uint32_ts. Not that you need any construction for them, but still.

Caveat: In both cases, you must not return p from the scope you're in, since it is a non-owning pointer, and the memory will be freed when you leave the scope. p is for local work only. If you want to keep the memory out-of-scope you have to return the unique_ptr.

2 Comments

But wouldn't the storage be reclaimed as soon as allocated goes out of scope, while p may still be around?
@alain: Of course it will - unless the unique_ptr is returned from the scope. I'll edit to warn about this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.