2013-03-08 23 views
8

In boost::interprocess documentazione si dice come requisito per contenitori da memorizzare nella memoria condivisa:std :: vector soddisfa i requisiti del contenitore per gli allocatori Boost.Interprocess?

  1. contenitori STL possono non presumere che la memoria allocata con un allocatore può essere deallocato con altri allocators dello stesso tipo. Tutti gli oggetti allocatori devono essere uguali solo se la memoria allocata con un oggetto può essere deallocata con l'altro e questo può essere verificato solo con operator==() in fase di esecuzione.
  2. I puntatori interni dei contenitori devono essere del tipo allocator::pointer ei contenitori non possono assumere che allocator::pointer sia un puntatore non elaborato.
  3. Tutti gli oggetti devono essere distrutti mediante le funzioni allocator::construct e allocator::destroy.

Sto utilizzando gcc 4.7.1 con -std = C++ 11 (e aumenta 1.53). È sicuro utilizzare il tipo ShmVector sotto definito?

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

Ho provato un processo fittizio che utilizza questo tipo, e sembra si sta lavorando, ma non sono ancora sicuro che il vettore in gcc4.7.1 non soddisfa tutti i requisiti. Non sono particolarmente sicuro del primo requisito.

#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

Secondo lo standard, dovrebbe andare bene. – Xeo

+0

@Xeo Non ne sono così sicuro. Lo standard dice che le implementazioni STL sono libere di assumere un allocatore dello stesso tipo in grado di deallocare la memoria; la maggior parte delle implementazioni non si basano su questo, ma dovresti controllare la documentazione della libreria 'std'. Tuttavia, data la prevalenza di 'g ++' e 'libstdC++', sarei sorpreso se Boost non ti avvisasse esplicitamente di incompatibilità. –

+0

@Xeo Ho trovato nello standard che il punto 3 deve essere vero per tutti gli std :: container: 23.2.1.3. Ma non è stato possibile trovare nulla per il proiettile 1 e 2. –

risposta

0

In C++ 11 le regole di allocatore sono leggermente cambiate, ma non penso che influenzi la tua domanda.

Probabilmente vorrai sapere prima cosa dice lo standard al riguardo. Ma in realtà dovresti controllare se la tua specifica implementazione STL è conforme allo standard e non contiene bug.

Per la seconda parte raccomando vivamente di andare a fonti e di controllarlo, in realtà non è così difficile.

Inoltre, si potrebbe scrivere i test per vedere se in realtà è perfettamente funzionante:

  • Crea allocatore personalizzato:
    • usare un certo tipo personalizzato come puntatore, puntatore const;
    • In construct(), destruct() numero di chiamate;
  • Creare YourCustomType da utilizzare con l'allocatore che conteggia anche il numero di costruzioni/distruzioni.
  • Ora, crea std::vetor<YourCustomType, YourCustomAllocator<YourCustomType>> esempio, inserire alcuni elementi, deselezionare il vettore, distruggerlo e vedere se:
    • numero di construct()destruct() chiamate è uguale al numero di costruzioni distruzioni di YourCustomType.
    • typeid(YourCustomAllocator::pointer) == typeid(std::vetor<YourCustomType, YourCustomAllocator<YourCustomType>>::pointer)

è così che si può essere sicuri che si applicano tutte le restrizioni.

Per quanto riguarda la prima parte della domanda, ecco uno old C++ standard (non C++ 11).

Non c'è modo (il vettore correttamente implementato) prenderà un allocatore dal nulla. Userà qualsiasi allocatore che fornisci e lo userà per tutto. Per quanto riguarda l'operatore ==, è implementato nell'allocatore di boost e quindi è il problema di boost per far funzionare l'operatore == come richiedono. Sebbene non sia stato possibile trovare la conferma nello standard.

A meno che non ci sia un bug, std::vector<T, YourAllocator>::pointer dovrebbe essere il puntatore dell'allocatore. cppreference.com says that, e lo standard says that, (cercare "classe Template vettore"):

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

Anche se lo stesso standard dice questo circa allocators: Implementazioni di contenitori descritti nella presente norma internazionale sono autorizzati a supporre che la loro Allocator parametro di modello soddisfa i seguenti due requisiti aggiuntivi oltre a quelli riportati nella Tabella 6.

istanze --Tutte di un dato tipo allocatore devono essere inter mutevole e confronta sempre uguali tra loro.

--Il typedef puntatore membri, const_pointer, size_type e diffe- ence_type devono essere T *, T const *, size_t, e ptrdiff_t, rispettivamente.

Quindi, in realtà lo standard non consente l'utilizzo di alcun tipo di puntatore, ma la mia ipotesi è che le implementazioni STL effettive funzioneranno.

Basta selezionare la realizzazione std::vector<T>::clear() metodo per vedere se allocatore :: distruggere è chiamato. Controllare l'implementazione del metodo std::vector<T>::resize() per verificare se si utilizza allocator :: construct. Non sono stato in grado di trovare il requisito di chiamare destroy e construct in the standard.

0

Penso che la risposta sia no. Poiché in pratica (in C++ 98) e in teoria (standard C++ 11), il puntatore std::vector non può essere diverso da T*.

Ecco perché boost::interprocess::vector<T> utilizza boost::container::vector<T, boost::interprocess::allocator<T>> (anziché std::vector<T, boost::interprocess::allocator<T>>).