2013-03-08 22 views
8

Trong boost::interprocess tài liệu hướng dẫn người ta nói như yêu cầu đối với các container được lưu trữ trong bộ nhớ chia sẻ:Liệu std :: vector có đáp ứng các yêu cầu vùng chứa cho các trình phân bổ Boost.Interprocess không?

  1. STL container có thể không thừa nhận rằng bộ nhớ được phân bổ với một cấp có thể được deallocated với allocators khác cùng loại. Tất cả các đối tượng cấp phát phải so sánh chỉ bằng nhau nếu bộ nhớ được cấp phát với một đối tượng có thể được deallocated với một đối tượng khác, và điều này chỉ có thể được kiểm tra với operator==() khi chạy.
  2. Con trỏ bên trong của bộ chứa phải thuộc loại allocator::pointer và vùng chứa có thể không giả định allocator::pointer là con trỏ thô.
  3. Tất cả các đối tượng phải được xây dựng phá hủy thông qua các chức năng allocator::constructallocator::destroy.

Tôi đang sử dụng gcc 4.7.1 với -std = C++ 11 (và tăng 1.53). Có an toàn không khi sử dụng loại ShmVector được xác định dưới đây?

typedef boost::interprocess::allocator<int, 
    boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator; 
typedef std::vector<int, ShmemAllocator> ShmVector; 

Tôi đã thử một trình giả trong đó sử dụng loại này, và có vẻ nó đang làm việc, nhưng tôi vẫn không chắc chắn rằng các vector trong gcc4.7.1 không đáp ứng tất cả các yêu cầu. Tôi đặc biệt không chắc chắn về yêu cầu đầu tiên.

#include <iostream> 
#include <boost/interprocess/allocators/allocator.hpp> 
#include <boost/interprocess/managed_shared_memory.hpp> 
#include <vector> 
#include <cstdlib> //std::system 

typedef boost::interprocess::allocator<int, 
     boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator; 
typedef std::vector<int, ShmemAllocator> ShmVector; 

int main(int argc, char *argv[]) 
{ 
    if(argc == 1){ //Parent process 

     struct shm_remove 
     { 
      shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); } 
      ~shm_remove(){ boost::interprocess::shared_memory_object::remove("MySharedMemory"); } 
     } remover; 

     //Create a new segment with given name and size 
     boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, 
       "MySharedMemory", 65536); 

     //Initialize shared memory STL-compatible allocator 
     const ShmemAllocator allocator(segment.get_segment_manager()); 

     ShmVector* v = segment.construct<ShmVector>("ShmVector")(allocator); 
     v->push_back(1); v->push_back(2); v->push_back(3); 

     //Launch child process 
     std::string s(argv[0]); s += " child "; 
     if(0 != std::system(s.c_str())) 
      return 1; 

    } else { // Child process 

     //Open the managed segment 
     boost::interprocess::managed_shared_memory segment(
       boost::interprocess::open_only, "MySharedMemory"); 

     //Find the vector using the c-string name 
     ShmVector *v = segment.find<ShmVector>("ShmVector").first; 

     for (const auto& i : *v) { 
      std::cout << i << " "; 
     } 
     std::cout << std::endl; 

    } 
} 
+1

Theo tiêu chuẩn, sẽ ổn thôi. – Xeo

+0

@Xeo Tôi không chắc lắm. Tiêu chuẩn nói rằng việc triển khai STL là miễn phí để giả sử một người cấp phát cùng loại có thể giải quyết bộ nhớ; hầu hết các triển khai không dựa vào điều này, nhưng bạn nên kiểm tra tài liệu của thư viện 'std'. Tuy nhiên, với sự phổ biến của 'g ++' và' libstdC++ ', tôi sẽ ngạc nhiên nếu Boost không cảnh báo bạn về sự không tương thích một cách rõ ràng. –

+0

@Xeo Tôi đã tìm thấy trong tiêu chuẩn, dấu đầu dòng 3 đó là đúng đối với tất cả std :: containers: 23.2.1.3. Nhưng không thể tìm thấy bất cứ điều gì cho bullet 1 và 2. –

Trả lời

0

Trong quy tắc phân bổ C++ 11 có thay đổi đôi chút, nhưng tôi không nghĩ rằng nó ảnh hưởng đến câu hỏi của bạn.

Bạn có thể muốn biết đầu tiên tiêu chuẩn nói gì về nó. Nhưng bạn thực sự muốn kiểm tra xem việc triển khai STL cụ thể của bạn có tuân theo tiêu chuẩn và không chứa lỗi hay không.

Đối với phần thứ hai, tôi khuyên bạn nên truy cập vào các nguồn và chỉ kiểm tra điều đó, nó không thực sự khó.

Ngoài ra, bạn có thể viết các bài kiểm tra của bạn để xem nếu nó thực sự hoạt động bình thường:

  • Tạo tùy chỉnh cấp phát:
    • sử dụng một số loại tùy chỉnh như con trỏ, con trỏ const;
    • Trong construct(), destruct() đếm số cuộc gọi;
  • Tạo YourCustomType để sử dụng với người cấp phát cũng tính số lượng công trình/hủy.
  • Bây giờ, tạo std::vetor<YourCustomType, YourCustomAllocator<YourCustomType>> dụ, chèn một số yếu tố, xóa các vector, tiêu diệt nó và xem nếu:
    • số construct()destruct() cuộc gọi bằng số công trình tàn phá của YourCustomType.
    • typeid(YourCustomAllocator::pointer) == typeid(std::vetor<YourCustomType, YourCustomAllocator<YourCustomType>>::pointer)

Đó là cách bạn có thể chắc chắn rằng tất cả các hạn chế được áp dụng.

Đối với phần đầu tiên của câu hỏi, dưới đây là old C++ standard (không phải C++ 11).

Không có cách nào (được triển khai đúng) vectơ sẽ lấy một bộ phân bổ không có nơi nào. Nó sẽ sử dụng bất kỳ cấp phát nào bạn cung cấp và sẽ sử dụng nó cho mọi thứ. Đối với toán tử ==, nó được thực thi trong bộ cấp phát của boost và do đó nó là vấn đề của boost để làm cho toán tử == hoạt động khi chúng yêu cầu. Mặc dù tôi không thể tìm thấy xác nhận trong số standard.

Trừ khi có lỗi, std::vector<T, YourAllocator>::pointer phải là con trỏ của người cấp phát. cppreference.com says that, và các tiêu chuẩn says that, (tìm kiếm "vector lớp Mẫu"):

typedef typename Allocator::pointer    pointer; 
    typedef typename Allocator::const_pointer   const_pointer; 

Mặc dù cùng một tiêu chuẩn nói này về allocators: Triển khai các container được mô tả trong tiêu chuẩn quốc tế này được phép giả định rằng cấp phát của họ thông số mẫu đáp ứng hai yêu cầu bổ sung sau ngoài các yêu cầu trong Bảng 6.

--Tất cả các trường hợp của một loại cấp phát cụ thể được yêu cầu phải thay đổi và luôn luôn so sánh với nhau.

--Thư typedef thành viên con trỏ, const_pointer, size_type, và differ- ence_type bắt buộc phải được T *, T const *, size_t, và ptrdiff_t, tương ứng.

Vì vậy, tiêu chuẩn thực sự không cho phép sử dụng bất kỳ loại con trỏ nào, nhưng tôi đoán là triển khai STL thực tế sẽ hoạt động.

Chỉ cần kiểm tra triển khai phương pháp std::vector<T>::clear() để xem liệu trình phân bổ :: hủy có được gọi hay không. Kiểm tra triển khai thực hiện của phương thức std::vector<T>::resize() để xem liệu trình phân bổ :: cấu trúc có được sử dụng hay không. Tôi đã không thể tìm thấy yêu cầu gọi phá hủy và xây dựng trong the standard.

0

Tôi nghĩ câu trả lời là không. Bởi vì trong thực tế (trong C++ 98) và theo lý thuyết (chuẩn C++ 11), con trỏ std::vector không thể là cái gì khác hơn là T*.

Đó là lý do tại sao boost::interprocess::vector<T> sử dụng boost::container::vector<T, boost::interprocess::allocator<T>> (thay vì std::vector<T, boost::interprocess::allocator<T>>).

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