2013-09-05 64 views
6

Tôi đang cố gắng để thực hiện sự liên kết 16-byte của mảng tĩnh đơn giản sử dụng std :: aligned_storage mẫu:Gắn mảng tĩnh nhờ sủ dụng std :: aligned_storage

#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 
} 

tôi nhận được biên dịch báo lỗi sau:

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

Sau đó, tôi đã cố gắng để sử dụng rõ ràng đúc con trỏ:

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

nhưng điều này cũng mang lại biên dịch báo lỗi:

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

Ai có thể gợi ý cho tôi cách sắp xếp mảng tĩnh nhờ sủ dụng std :: aligned_storage chính xác?

+0

Tại sao bạn không sử dụng con trỏ được trả về bởi 'mới'? – avakar

+2

@avakar con trỏ được trả về bởi 'new' không có liên kết mở rộng. –

+0

@ R.MartinhoFernandes: Tôi nghĩ avakar nói về vị trí mới (được căn chỉnh). (xem câu trả lời của tôi) – Jarod42

Trả lời

7

Bạn có thể sử dụng:

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

và sau đó bạn có thể sử dụng:

floats[0] = 1.f; 

không reinterpret_cast ở tất cả :)

+0

Tôi sẽ lo lắng về việc sử dụng vị trí mới cho phân bổ mảng vì không gian bổ sung mà phân bổ * có thể * cần để theo dõi kích thước phân bổ, được xác định bằng thực thi. –

+0

@FabioA .: Thật vậy, để hoàn toàn an toàn, chúng ta phải lặp lại để tạo vị trí 'SIZE' mới: (hoặc sử dụng' std :: array 'hoặc tương tự. – Jarod42

5

mas không phải là con trỏ. reinterpret_cast phải liên quan đến con trỏ, tham chiếu hoặc các kiểu tích phân và chỉ trong một số kết hợp: con trỏ đến và từ các loại tích phân, con trỏ đến con trỏ, tham chiếu đến tham chiếu hoặc loại tích phân cho chính nó. Trong trường hợp này, bạn đang cố gắng để trường hợp một số std::aligned_storage<32u, 16u>::type cho một con trỏ. Tốt nhất bạn có thể nhận được từ điều này sẽ là một tham chiếu đến con trỏ đúc, nhưng đó là không được phép & dagger ;.

Hãy thử truyền địa chỉ của nó sang loại con trỏ khác thay thế: reinterpret_cast<float*>(&mas);.


& dagger; cho vui: tồi tệ nhất bạn có thể nhận được sẽ là nếu std::aligned_storage<32u, 16u>::type là một loại con trỏ. Đó là nghi ngờ, kể từ khi con trỏ 32-byte không phổ biến, nhưng nó có thể xảy ra cho std::aligned_storage<8u, 8u>::type, ví dụ, trong một thư viện chuẩn rất khó chịu. Hãy gọi nó là Hell ++. Vì vậy, trong Hell ++ nó sẽ biên dịch tốt, và bạn sẽ kết thúc việc đúc kiểu con trỏ đến một kiểu con trỏ khác, và sau đó làm tất cả các lỗi trên nó như dereferencing nó. Điều này sẽ là thảm họa, bởi vì nếu std::aligned_storage<32u, 16u>::type là một loại con trỏ, các đối tượng sẽ không có địa chỉ cho bộ nhớ, nhưng chúng sẽ bộ nhớ thay thế.

+0

Nó hoạt động, nhưng tôi có thể shure, mà mas_ thực sự là 16-byte phù hợp? – gorill

+2

@gorill nếu không, hãy gửi một lỗi cho việc triển khai thư viện chuẩn của bạn.(bạn có thể kiểm tra nó bằng cách reinterpret_casting con trỏ như một số nguyên và kiểm tra nếu nó chia hết cho 16) –

+0

'reinterpret_cast (mas)' sẽ giải thích mẫu bit tại 'mas' như một con trỏ - không thể là những gì được dự định. Thay vào đó hãy sử dụng 'reinterpret_cast (& mas)'. –

1

Chỉ cần

alignas(16) float mas[SIZE]; 

std::aligned_storage là một C++ 03 di tích đến từ boost.

+0

Tôi đã thử, nhưng trình biên dịch của tôi (gcc 4.7) – gorill

+1

@gorill Yeah 4.7 không hỗ trợ nó Hãy thử cập nhật trình biên dịch của bạn lên 4.8. – user1095108

+2

'aligned_storage' không phải là một di tích C++ 03. Nó sắp xếp lưu trữ thô, trong khi' alignas' căn chỉnh các đối tượng. Mặc dù nó không tạo nên sự khác biệt lớn ở đây trong trường hợp cụ thể này, 'aligned_storage' cung cấp chức năng không cần thiết. –