2011-01-03 29 views
7

C++ hợp pháp sau có hành vi được xác định rõ ràng không?mảng char làm dung lượng lưu trữ cho vị trí mới

class my_class { ... }; 

int main() 
{ 
    char storage[sizeof(my_class)]; 
    new ((void *)storage) my_class(); 
} 

Hoặc điều này có vấn đề do cân nhắc về chuyển đổi con trỏ/căn chỉnh không?

+0

Đối với tôi, điều đó là tốt. –

+2

Không, dấu ba chấm không hợp pháp trong ngữ cảnh đó ... (Gợi ý: nếu bạn muốn hỏi xem mã có được xác định rõ không, nó phải biên dịch trước.) – GManNickG

+0

Bất kỳ ai hãy nói cho tôi biết cách sử dụng điều trên là gì trong thế giới pogramming thực sự. – vrbilgi

Trả lời

12

Có, nó có vấn đề. Bạn chỉ đơn giản là không có đảm bảo rằng bộ nhớ được căn chỉnh đúng cách.

Trong khi các thủ thuật khác nhau tồn tại để có được lưu trữ với sự liên kết thích hợp, tốt nhất bạn nên dùng Boost's hoặc C++ 0x's aligned_storage, ẩn các thủ thuật này khỏi bạn.

Sau đó, bạn chỉ cần:

// C++0x 
typedef std::aligned_storage<sizeof(my_class), 
           alignof(my_class)>::type storage_type; 

// Boost 
typedef boost::aligned_storage<sizeof(my_class), 
         boost::alignment_of<my_class>::value>::type storage_type; 

storage_type storage; // properly aligned 
new (&storage) my_class(); // okay 

Lưu ý rằng trong C++ 0x, sử dụng thuộc tính, bạn có thể chỉ làm điều này:

char storage [[align(my_class)]] [sizeof(my_class)]; 
+0

Cảm ơn, điều này rất hữu ích để biết. – bluescarni

+0

Xin lỗi, chưa hoàn toàn ở đó :) Theo như tôi đã hiểu, loại lưu trữ là một loại loại số nguyên dựng sẵn. Làm thế nào để tôi sử dụng nó? Tôi có thể tự do chuyển sang loại my_class qua void * không? – bluescarni

+0

Xin lỗi, tôi có nghĩa là để nói: "đúc tự do qua lại từ/đến con trỏ đến trường hợp my_class" ... Hoặc một cái gì đó như thế :) – bluescarni

2

Ít nhất có vấn đề do căn chỉnh.

Trên hầu hết cấu trúc không phải của Intel, mã sẽ tạo ra "lỗi bus" do căn chỉnh sai hoặc cực kỳ chậm do bẫy bộ xử lý cần thiết để sửa lỗi truy cập bộ nhớ chưa được ký.

Trên kiến ​​trúc Intel, điều này thường sẽ chậm hơn một chút so với bình thường. Ngoại trừ nếu một số hoạt động SSE có liên quan, thì nó cũng có thể bị lỗi.

0

Đoạn char có thể không được căn chỉnh chính xác cho kích thước myclass. Trên một số kiến ​​trúc, điều đó có nghĩa là truy cập chậm hơn, và trên những kiến ​​trúc khác, nó có nghĩa là một sự cố. Thay vì char, bạn nên sử dụng loại có liên kết bằng hoặc lớn hơn số của struct, được đưa ra bởi yêu cầu căn chỉnh lớn nhất của bất kỳ thành viên nào của nó.

#include <stdint.h> 

class my_class { int x; }; 

int main() { 
    uint32_t storage[size]; 
    new(storage) my_class(); 
} 

Bố trí đủ bộ nhớ cho một my_class dụ, tôi nghĩ size nên được sizeof(my_class)/sizeof(T), nơi T là tùy theo loại bạn sử dụng để có được sự liên kết chính xác.

+0

"... có liên kết bằng hoặc lớn hơn cấu trúc, được đưa ra bởi yêu cầu căn chỉnh lớn nhất của bất kỳ thành viên nào" Tôi không nghĩ rằng điều này được đảm bảo, căn chỉnh hoàn toàn được thực hiện xác định. (Nghĩa là, sự liên kết của nó không được đảm bảo nhất thiết phải là sự liên kết của thành viên chặt chẽ nhất.) Ngoài ra, 'int' có thể lớn hơn 32 bit. – GManNickG

+0

@GMan: Bạn nói đúng. Tuy nhiên, nó hoạt động trong hầu hết các trường hợp. Ở đây, có một liên kết: http://stackoverflow.com/questions/364483/determining-the-alignment-of-c-c-structures-in-relation-to-its-members –

3

Khi mọi người đã đề cập ở đây, điều này sẽ không nhất thiết phải làm việc do hạn chế liên kết. Có một số cách để căn chỉnh đúng. Đầu tiên, nếu bạn có trình biên dịch C++ 0x, bạn có thể sử dụng toán tử alignof để cố gắng căn chỉnh đúng. Thứ hai, bạn có thể tự động phân bổ mảng ký tự, vì bộ nhớ từ toán tử mới được đảm bảo được căn chỉnh theo cách mà bất kỳ thứ gì có thể sử dụng nó một cách chính xác. Thứ ba, bạn có thể thử lưu trữ mảng ký tự trong một liên minh với một số loại có liên kết tối đa có thể trên hệ thống của bạn; Tôi tin rằng this article có một số thông tin về nó (mặc dù nó được thiết kế cho C++ 03 và chắc chắn là không tốt như các nhà điều hành alignof đó sắp ra sớm).

Hy vọng điều này sẽ hữu ích!

2

Trong trường hợp bất kỳ ai muốn tránh Boost hoặc C++ 1x, mã hoàn chỉnh này hoạt động cả trong GCC và MSVC. Mã cụ thể MSVC dựa trên số aligned_memory.h của Chromium. Nó phức tạp hơn một chút so với phiên bản GCC, bởi vì __declspec(align(.)) của MSVC chỉ chấp nhận các giá trị căn chỉnh chữ, và điều này được làm việc xung quanh bằng cách sử dụng chuyên môn mẫu cho tất cả các sắp xếp có thể.

#ifdef _MSC_VER 

template <size_t Size, size_t Align> 
struct AlignedMemory; 

#define DECLARE_ONE_ALIGNED_MEMORY(alignment) \ 
template <size_t Size> \ 
struct __declspec(align(alignment)) AlignedMemory<Size, alignment> { \ 
    char mem[Size]; \ 
}; 

DECLARE_ONE_ALIGNED_MEMORY(1) 
DECLARE_ONE_ALIGNED_MEMORY(2) 
DECLARE_ONE_ALIGNED_MEMORY(4) 
DECLARE_ONE_ALIGNED_MEMORY(8) 
DECLARE_ONE_ALIGNED_MEMORY(16) 
DECLARE_ONE_ALIGNED_MEMORY(32) 
DECLARE_ONE_ALIGNED_MEMORY(64) 
DECLARE_ONE_ALIGNED_MEMORY(128) 
DECLARE_ONE_ALIGNED_MEMORY(256) 
DECLARE_ONE_ALIGNED_MEMORY(512) 
DECLARE_ONE_ALIGNED_MEMORY(1024) 
DECLARE_ONE_ALIGNED_MEMORY(2048) 
DECLARE_ONE_ALIGNED_MEMORY(4096) 

#else 

template <size_t Size, size_t Align> 
struct AlignedMemory { 
    char mem[Size]; 
} __attribute__((aligned(Align))); 

#endif 

template <class T> 
struct AlignedMemoryFor : public AlignedMemory<sizeof(T), __alignof(T)> {}; 
Các vấn đề liên quan