6

I'm trying to implement 16-byte alignment of simple static array using std::aligned_storage pattern:

#include <type_traits>
int main()
{
    const size_t SIZE = 8;
    using float_16 = std::aligned_storage<sizeof(float) * SIZE, 16>::type;
    float_16 mas;
    new(&mas) float[SIZE];//Placement new. Is this necessary? 

    mas[0]=1.f;//Compile error while attempting to set elements of aligned array
}

I get the following compile-error:

no match for «operator[]» in «mas[0]»

Then I tried to use explicit pointer casting:

float* mas_ = reinterpret_cast<float*>(mas); 

but this also yields compile-error:

invalid cast from type «float_16 {aka std::aligned_storage<32u, 16u>::type}» to type «float*»

Can anybody suggest me how align static array using std::aligned_storage correctly?

gorill
  • 1,623
  • 3
  • 20
  • 29

3 Answers3

8

You may use:

float* floats = new (&mas) float[SIZE];

and then you can use:

floats[0] = 1.f;

no reinterpret_cast at all :)

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I'd worry about using placement new for an array allocation because of the extra space the allocation *might* need in order to keep track of the allocation size, which is afaik implementation-defined. – Fabio A. Mar 27 '17 at 13:09
  • @FabioA.: Indeed, to be perfectly safe, we have to loop to make `SIZE` placement new :( or to use `std::array` or similar. – Jarod42 Mar 27 '17 at 17:38
5

mas is not a pointer. reinterpret_cast must involve exclusively pointer, reference, or integral types, and only in some combinations: pointers to and from integral types, pointers to pointers, references to references, or an integral type to itself. In this case you are trying to case an std::aligned_storage<32u, 16u>::type to a pointer. The best you could get from this would be a reference to pointer cast, but that's not allowed†.

Try casting its address to another pointer type instead: reinterpret_cast<float*>(&mas);.


† for fun: the worst you could get would be if std::aligned_storage<32u, 16u>::type was a pointer type. It's doubtful, since 32-byte pointers are not common, but it could happen for std::aligned_storage<8u, 8u>::type, for example, in a very nasty standard library. Let's call it Hell++. So, in Hell++ it would compile fine, and you would end up casting the pointer type to another pointer type, and then doing all nasties on it like dereferencing it. This would be disastrous, because if std::aligned_storage<32u, 16u>::type was a pointer type, objects wouldn't have the address for the storage, but they would be the storage instead.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • It works, but can I be shure, that mas_ is really 16-byte aligned? – gorill Sep 05 '13 at 14:04
  • 2
    @gorill if it isn't, file a bug for your standard library implementation. (you can test it by reinterpret_casting the pointer as an integer and checking if it's divisible by 16) – R. Martinho Fernandes Sep 05 '13 at 14:07
  • `reinterpret_cast(mas)` will interpret the bit pattern at `mas` as a pointer - that can't be what was intended. Use `reinterpret_cast(&mas)` instead. – Sebastian Redl Sep 05 '13 at 14:41
  • @SebastianRedl oh, true! He wants an array, not a pointer. Ooops. Thanks. (And now I feel silly, after posting that note and causing the same thing here) – R. Martinho Fernandes Sep 05 '13 at 14:42
  • @R. Martinho Fernandes, I tried Your suggetion, but get runtime-error. Please, see addition part in my question. – gorill Sep 05 '13 at 15:52
  • 5
    Oh, please. I'm going to be blunt. You need to go learn some basic C++ before you start messing with `reinterpret_cast` and `aligned_storage`. – R. Martinho Fernandes Sep 05 '13 at 16:12
  • Recommended reading: http://stackoverflow.com/a/6445794/46642 and http://stackoverflow.com/q/5870038/46642 and something about out parameters or return values. – R. Martinho Fernandes Sep 05 '13 at 16:52
  • @ R. Martinho Fernandes, sorry - I really screwed up)))) it is my stupid and apparent mistake. – gorill Sep 05 '13 at 17:13
3

Just do

alignas(16) float mas[SIZE];

std::aligned_storage is a C++03 relic coming from boost.

user1095108
  • 14,119
  • 9
  • 58
  • 116
  • 1
    @gorill Yeah 4.7 does not support it. Try updating your compiler to 4.8. – user1095108 Sep 05 '13 at 20:24
  • 3
    `aligned_storage` is not a C++03 relic. It aligns raw storage, while `alignas` aligns objects. Those are different purposes. Even though it does not make a big difference here in this particular case, `aligned_storage` provides non-redundant functionality. – R. Martinho Fernandes Sep 06 '13 at 08:53
  • @R.MartinhoFernandes Nothing you couldn't replace with a `typedef` or a `using`. – user1095108 Sep 06 '13 at 10:30