2010-05-06 37 views
15

Tôi sắp xếp chức năng ổ cắm không gian người dùng Linux trong một số C++ cho một hệ thống nhúng (có, đây có thể là phát minh lại bánh xe lần nữa).Sử dụng read() trực tiếp vào C++ std: vector

Tôi muốn cung cấp tính năng đọc và ghi bằng cách sử dụng vectơ.

Làm việc viết khá dễ dàng, tôi chỉ có thể vượt qua &myvec[0] và tránh sao chép không cần thiết. Tôi muốn làm như vậy và đọc trực tiếp vào một véc tơ, thay vì đọc vào một bộ đệm char sau đó sao chép tất cả vào một vectơ mới được tạo ra.

Bây giờ, tôi biết số lượng dữ liệu tôi muốn đọc và tôi có thể phân bổ một cách thích hợp (vec.reserve()). Tôi cũng có thể đọc vào &myvec[0], mặc dù đây có thể là một IDEA VERY BAD. Rõ ràng làm điều này không cho phép myvec.size trả lại bất cứ điều gì hợp lý. Có cách nào để làm điều này rằng:

  1. Không hoàn toàn cảm thấy chút kinh ngạc từ một an toàn/C++ quan điểm
  2. Không liên quan đến hai bản sao của khối dữ liệu - một lần từ hạt nhân để không gian sử dụng và một lần từ một bộ đệm kiểu C char * thành một vector C++.
+0

Một vectơ về cái gì? –

+0

Một vectơ của ký tự (tốt, byte)! – Joe

+0

Bạn có thể muốn sử dụng 'uint8_t' hoặc' unsigned char' cho byte. – tzaman

Trả lời

22

Sử dụng resize() thay vì reserve(). Điều này sẽ thiết lập kích thước của vectơ một cách chính xác - và sau đó, &myvec[0], như thường lệ, được bảo đảm để trỏ đến một khối bộ nhớ.

Chỉnh sửa: Sử dụng &myvec[0] làm con trỏ tới mảng cơ bản cho cả đọc và viết là an toàn và đảm bảo hoạt động theo tiêu chuẩn C++. Dưới đây là những gì Herb Sutter has to say:

Vậy tại sao mọi người liên tục hỏi liệu các phần tử của std :: vector (hoặc std :: array) có được lưu trữ liên tục không? Lý do rất có thể là họ muốn biết liệu họ có thể ho lên các con trỏ đến các bên trong để chia sẻ dữ liệu, hoặc đọc hay viết, với mã khác đề cập đến các mảng C. Đó là cách sử dụng hợp lệ và đủ quan trọng để đảm bảo tiêu chuẩn.

+0

Đó là đào, và chắc chắn câu trả lời điểm 2 (thử nghiệm và hoạt động quá, cảm ơn! :-)), nhưng cách tiếp cận này an toàn và sạch sẽ, hoặc là có cách nào khác? Tôi không thể không cảm thấy rằng việc truyền địa chỉ của các khối bộ nhớ liền kề vectơ để viết vào có vẻ nguy hiểm? – Joe

+0

@Joe: Theo lời của Herb Sutter: "Cringe not" - nó hoàn toàn an toàn. Xem chỉnh sửa của tôi ở trên và liên kết đến mục blog của Herb Sutter. –

+0

Tuyệt vời! Cảm ơn :-) Như bao giờ stackoverflow.com cung cấp! – Joe

1

Giả sử đây là cấu trúc POD, hãy gọi resize thay vì reserve. Bạn có thể định nghĩa một hàm tạo mặc định rỗng nếu bạn thực sự không muốn dữ liệu được lấy ra trước khi bạn điền vào vectơ.

Đó là mức độ hơi thấp, nhưng ngữ nghĩa của việc xây dựng các cấu trúc POD là cố ý tối tăm. Nếu memmove được phép sao chép chúng, tôi không thấy lý do tại sao ổ đọc không nên.

CHỈNH SỬA: ah, byte, không phải cấu trúc. Vâng, bạn có thể sử dụng cùng một thủ thuật và xác định cấu trúc chỉ với char và một hàm tạo mặc định bỏ qua để khởi tạo nó ... nếu tôi đoán chính xác bạn quan tâm và đó là lý do bạn muốn gọi reserve thay vì resize trong địa điểm đầu tiên.

1

Nếu bạn muốn vector phản ánh lượng dữ liệu đã đọc, hãy gọi resize() hai lần. Một lần trước khi đọc, để cho mình không gian để đọc vào. Một lần nữa sau khi đọc, để thiết lập kích thước của vector với số byte thực sự đọc. reserve() không tốt, vì việc đặt trước cuộc gọi không cho phép bạn truy cập vào bộ nhớ được phân bổ cho dung lượng.

resize() đầu tiên sẽ không là thành phần của vectơ, nhưng điều này không có khả năng tạo ra nhiều chi phí hiệu năng. Nếu có thì bạn có thể thử đề xuất của Potatoswatter, hoặc bạn có thể từ bỏ kích thước của vector phản ánh kích thước của dữ liệu đọc, và thay vào đó chỉ resize() nó một lần, sau đó sử dụng lại chính xác như bạn sẽ cấp phát bộ đệm trong C

Hiệu suất-khôn ngoan, nếu bạn đang đọc từ một ổ cắm trong chế độ người dùng, rất có thể bạn có thể dễ dàng xử lý dữ liệu nhanh như nó đi vào. Có thể không nếu bạn đang kết nối với máy khác trên mạng LAN gigabit, hoặc nếu máy của bạn thường xuyên chạy CPU 100% hoặc băng thông bộ nhớ 100%. Một chút sao chép thêm hoặc memsetting là không có vấn đề lớn nếu bạn cuối cùng sẽ chặn trên một cuộc gọi read anyway.

Giống như bạn, tôi muốn tránh bản sao phụ trong không gian người dùng, nhưng không vì lý do hiệu suất, chỉ vì nếu tôi không làm điều đó, tôi không phải viết mã cho nó.

+0

Thông thường tôi sẽ không quan tâm đến bản sao phụ thực sự, nhưng tôi đang trên một hệ thống thời gian thực với các nguồn lực thấp. Toàn bộ quá trình đọc/ghi không bị chặn. Tất nhiên, điều này rõ ràng dẫn đến các câu hỏi về các container STL trong một hệ thống thời gian thực so với việc cấp phát bộ nhớ tĩnh, v.v ... – Joe

1

Tôi sẽ chỉ thêm một giải thích ngắn gọn, vì câu trả lời đã được đưa ra. thay đổi kích thước() với đối số lớn hơn kích thước hiện tại sẽ thêm các phần tử vào bộ sưu tập và mặc định - khởi tạo chúng. Nếu Bạn tạo

std::vector<unsigned char> v; 

và sau đó thay đổi kích thước

v.resize(someSize); 

Tất cả các ký tự không dấu sẽ được khởi tạo là 0. Btw Bạn có thể làm tương tự với một constructor

std::vector<unsigned char> v(someSize); 

Vì vậy, về mặt lý thuyết nó có thể chậm hơn một chút so với mảng thô, nhưng nếu cách khác là sao chép mảng, thì tốt hơn.

Dự trữ chỉ chuẩn bị bộ nhớ, do đó không cần phân bổ lại, nếu các thành phần mới được thêm vào bộ sưu tập, nhưng Bạn không thể truy cập vào bộ nhớ đó.

Bạn phải nhận thông tin về số phần tử được ghi vào vectơ của bạn. Vectơ sẽ không biết gì về nó.

Các vấn đề liên quan