2017-06-04 2 views
0

Ich möchte erreichen, was in der Antwort auf this Frage erreicht wurde, aber für einen Vektor von Strings, d. Ich möchte in der Lage sein, gemeinsamen Code zu schreiben, der entweder mit Heap-Speicher oder Shared Memory verwendet werden kann. Ich habe den Code emuliert und eine Klasse geschrieben, um einen Vektor von Strings zu implementieren, der sowohl mit Heap-Speicher als auch mit gemeinsam genutztem Speicher funktionieren würde. Ich habe es größtenteils funktioniert. Wenn ich jedoch versuche, einen Shared-Memory-Vektor von Strings aus einem Heap-zugewiesenen Vektor von Strings zu initialisieren/erstellen, erhalte ich Kompilierungsfehler. In der Frage, auf die oben verwiesen wird, wurde Shared-Memory-Vektor aus einem nicht geteilten Speichervektor initialisiert (um zu zitieren "das funktioniert wegen ... MAGIC!"). Nicht sicher, ob es, weil diese Frage mit einem Vektor von Ints handelte, die leicht kopierbar und beweglich sind. Ich habe den Kopierkonstruktor für die Shared-Memory-String-Klasse zur Verfügung gestellt, aber es funktioniert immer noch nicht. Ich habe meinen Code unten zur Verfügung gestellt (den Code auskommentiert, der mir Kompilierungsfehler gibt). Jede Hilfe wird geschätzt. Vielen Dank.C++ Boost Interprozess Austausch (Kopie) nicht freigegebenen und geteilten Zeichenfolge Vektor

#include <boost/interprocess/managed_shared_memory.hpp> 
#include <boost/interprocess/allocators/allocator.hpp> 
#include <boost/interprocess/containers/vector.hpp> 
#include <boost/interprocess/containers/string.hpp> 
#include <boost/container/scoped_allocator.hpp> 
#include <iostream> 
#include <string> 
#include <sstream> 

namespace bip = boost::interprocess; 

namespace generic 
{ 

template <typename T, typename Alloc/* = std::allocator<T>*/ > 
using vector = bip::vector<T, typename Alloc::template rebind<T>::other >; 

template <typename Alloc/* = std::allocator<T>*/ > 
using GenericString = bip::basic_string<char, std::char_traits<char> 
          , typename Alloc::template rebind<char>::other>; 

template <typename Alloc> 
class String 
{ 
public: 
    typedef Alloc allocator_type; // ties in with uses_allocator/scoped_allocator 

    String(Alloc alloc = Alloc()) 
    : mString(alloc) 
    { 
    } 

    String(const std::string str, Alloc alloc = Alloc()) 
    : mString(str.c_str(), alloc) 
    { 
    } 

    String(const char* str, Alloc alloc = Alloc()) 
    : mString(str, alloc) 
    { 
    } 

    template <typename OtherAlloc> 
    String(String<OtherAlloc> const& other, Alloc alloc = Alloc()) 
    : mString(other.mString.begin(), other.mString.end(), alloc) 
    { 
    } 

    std::string ToString() { return std::string(mString.begin(), mString.end()); } 

    friend std::ostream& operator<<(std::ostream& os, const String& str) 
    { 
    os << str.mString; 
    return os; 
    } 

private: 
    template<typename OtherAlloc> friend struct String; 
    GenericString<Alloc> mString; 
}; 

template <typename Alloc> 
class StringVector 
{ 
public: 
    typedef Alloc allocator_type; // ties in with uses_allocator/scoped_allocator 
    typedef vector<String<Alloc>, Alloc> GenericStringVector; 
    using Iterator = typename GenericStringVector::iterator; 
    using ConstIterator = typename GenericStringVector::const_iterator; 

    StringVector(Alloc alloc = Alloc()) 
    : mStrings(alloc) 
    { 
    } 

    template <typename OtherAlloc> 
    StringVector(StringVector<OtherAlloc> const& other, Alloc alloc = Alloc()) 
    : mStrings(other.mStrings.begin(), other.mStrings.end(), alloc) 
    { 
    } 

    void Add(const String<Alloc> str) { mStrings.emplace_back(str); } 

    void Remove(Iterator iter) { mStrings.erase(iter); } 

    void Clear() { mStrings.clear(); } 

    void Print() const 
    { 
    std::cout << "["; 
    for (ConstIterator it = mStrings.begin(); it != mStrings.end(); it++) 
     std::cout << (it == mStrings.begin() ? "" : ", ") << *it; 
    std::cout << "]\n"; 
    } 

private: 
    template<typename OtherAlloc> friend struct StringVector; 
    GenericStringVector mStrings; 
}; 

} 

namespace heap 
{ 
    using VAlloc = std::allocator<void>; 
    using String = generic::String<VAlloc>; 
    using StringVector = generic::StringVector<VAlloc>; 
} 

namespace shared 
{ 
    using VAlloc =boost::container::scoped_allocator_adaptor< 
      bip::allocator<void, bip::managed_shared_memory::segment_manager> >; 

    using String = generic::String<VAlloc>; 
    using StringVector = generic::StringVector<VAlloc>; 
} 

int main(void) 
{ 
    struct shm_remove { 
     shm_remove() { bip::shared_memory_object::remove("MySharedMemory"); } 
     ~shm_remove() { bip::shared_memory_object::remove("MySharedMemory"); } 
    } remover; 

    std::cout << "Heap based storage: \n"; 
    heap::StringVector svec; 

    svec.Add(heap::String("test1")); 
    svec.Add(heap::String("test2")); 
    svec.Add(heap::String("test3")); 
    svec.Add(heap::String("test4")); 
    svec.Print(); 

    std::cout << "Shared memory storage: \n"; 
    bip::managed_shared_memory seg(bip::create_only, "MySharedMemory", 65536); 
    shared::VAlloc shalloc(seg.get_segment_manager()); 

    shared::StringVector sh_svec(shalloc); 
    sh_svec.Add(shared::String("test1", shalloc)); 
    sh_svec.Add(shared::String("test2", shalloc)); 
    sh_svec.Add(shared::String("test3", shalloc)); 
    sh_svec.Add(shared::String("test4", shalloc)); 
    sh_svec.Print(); 


    shared::StringVector sh_svec2(sh_svec, shalloc); 
    sh_svec2.Print(); 

    //shared::StringVector sh_svec3(svec, shalloc); // gives compile error :(
    //sh_svec3.Print(); 
} 

Einschließlich Kompilierungsfehlern:

In file included from src/test_string_vector.cc:5:0: 
/usr/include/boost/container/scoped_allocator.hpp: In instantiation of ‘boost::container::container_detail::scoped_allocator_adaptor_base<OuterAlloc>::scoped_allocator_adaptor_base() [with OuterAlloc = boost::interprocess::allocator<void, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> >]’: 
/usr/include/boost/container/scoped_allocator.hpp:963:7: required from ‘boost::container::scoped_allocator_adaptor<OuterAlloc, InnerAllocs>::scoped_allocator_adaptor() [with OuterAlloc = boost::interprocess::allocator<void, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> >; InnerAllocs = {}]’ 
/usr/include/boost/container/vector.hpp:1174:15: required from ‘void boost::container::vector<T, Allocator>::assign(FwdIt, FwdIt, typename boost::container::container_detail::enable_if_c<((! boost::container::container_detail::is_convertible<InIt, typename boost::container::allocator_traits<Allocator>::size_type>::value) && ((! boost::container::container_detail::is_input_iterator<InIt>::value) && (! boost::move_detail::is_same<typename boost::container::container_detail::version<Allocator>::type, boost::container::container_detail::integral_constant<unsigned int, 0u> >::value)))>::type*) [with FwdIt = boost::container::container_detail::vec_iterator<generic::String<std::allocator<void> >*, true>; T = generic::String<boost::container::scoped_allocator_adaptor<boost::interprocess::allocator<void, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > > >; Allocator = boost::container::scoped_allocator_adaptor<boost::interprocess::allocator<generic::String<boost::container::scoped_allocator_adaptor<boost::interprocess::allocator<void, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > > >, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > >; typename boost::container::container_detail::enable_if_c<((! boost::container::container_detail::is_convertible<InIt, typename boost::container::allocator_traits<Allocator>::size_type>::value) && ((! boost::container::container_detail::is_input_iterator<InIt>::value) && (! boost::move_detail::is_same<typename boost::container::container_detail::version<Allocator>::type, boost::container::container_detail::integral_constant<unsigned int, 0u> >::value)))>::type = void]’ 
/usr/include/boost/container/vector.hpp:864:7: required from ‘boost::container::vector<T, Allocator>::vector(InIt, InIt, const allocator_type&) [with InIt = boost::container::container_detail::vec_iterator<generic::String<std::allocator<void> >*, true>; T = generic::String<boost::container::scoped_allocator_adaptor<boost::interprocess::allocator<void, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > > >; Allocator = boost::container::scoped_allocator_adaptor<boost::interprocess::allocator<generic::String<boost::container::scoped_allocator_adaptor<boost::interprocess::allocator<void, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > > >, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > >; boost::container::vector<T, Allocator>::allocator_type = boost::container::scoped_allocator_adaptor<boost::interprocess::allocator<generic::String<boost::container::scoped_allocator_adaptor<boost::interprocess::allocator<void, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > > >, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > >]’ 
src/test_string_vector.cc:78:65: required from ‘generic::StringVector<Alloc>::StringVector(const generic::StringVector<OtherAlloc>&, Alloc) [with OtherAlloc = std::allocator<void>; Alloc = boost::container::scoped_allocator_adaptor<boost::interprocess::allocator<void, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > >]’ 
src/test_string_vector.cc:151:46: required from here 
/usr/include/boost/container/scoped_allocator.hpp:762:7: error: no matching function for call to ‘boost::interprocess::allocator<void, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> >::allocator()’ 
     {} 
    ^
In file included from /usr/include/boost/interprocess/segment_manager.hpp:38:0, 
       from /usr/include/boost/interprocess/detail/managed_memory_impl.hpp:30, 
       from /usr/include/boost/interprocess/managed_shared_memory.hpp:25, 
       from src/test_string_vector.cc:1: 
/usr/include/boost/interprocess/allocators/allocator.hpp:142:4: note: candidate: template<class T2> boost::interprocess::allocator<T, SegmentManager>::allocator(const boost::interprocess::allocator<T2, SegmentManager>&) 
    allocator(const allocator<T2, SegmentManager> &other) 
    ^
/usr/include/boost/interprocess/allocators/allocator.hpp:142:4: note: template argument deduction/substitution failed: 
In file included from src/test_string_vector.cc:5:0: 
/usr/include/boost/container/scoped_allocator.hpp:762:7: note: candidate expects 1 argument, 0 provided 
     {} 
    ^
In file included from /usr/include/boost/interprocess/segment_manager.hpp:38:0, 
       from /usr/include/boost/interprocess/detail/managed_memory_impl.hpp:30, 
       from /usr/include/boost/interprocess/managed_shared_memory.hpp:25, 
       from src/test_string_vector.cc:1: 
/usr/include/boost/interprocess/allocators/allocator.hpp:136:4: note: candidate: boost::interprocess::allocator<T, SegmentManager>::allocator(const boost::interprocess::allocator<T, SegmentManager>&) [with T = void; SegmentManager = boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index>] 
    allocator(const allocator &other) 
    ^
/usr/include/boost/interprocess/allocators/allocator.hpp:136:4: note: candidate expects 1 argument, 0 provided 
/usr/include/boost/interprocess/allocators/allocator.hpp:131:4: note: candidate: boost::interprocess::allocator<T, SegmentManager>::allocator(boost::interprocess::allocator<T, SegmentManager>::segment_manager*) [with T = void; SegmentManager = boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index>; boost::interprocess::allocator<T, SegmentManager>::segment_manager = boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index>] 
    allocator(segment_manager *segment_mngr) 
    ^
/usr/include/boost/interprocess/allocators/allocator.hpp:131:4: note: candidate expects 1 argument, 0 provided 
Makefile:16: recipe for target 'obj/test_string_vector.o' failed 
make: *** [obj/test_string_vector.o] Error 1 

Antwort

1

ich, dass ich jetzt Ihre Absicht zu verstehen. Sie dieses Stück Code, wo OtherAlloc = std :: allocator, Alloc = bi: allocator

template <typename OtherAlloc> 
    StringVector(StringVector<OtherAlloc> const& other, Alloc alloc = Alloc()) 
    : mStrings(other.mStrings.begin(), other.mStrings.end(), alloc) 
    { 
    } 

eine Kopie Konstruktor rufen Sie von Heap gemeinsam benutzten Typ

template <typename OtherAlloc> 
    String(String<OtherAlloc> const& other, Alloc alloc = Alloc()) 
    : mString(other.mString.begin(), other.mString.end(), alloc) 
    { 
    } 

Aber Schub zu konvertieren bereitgestellt :: interprocess :: vector :: assign (first, last) übergibt die Instanz Ihres Allokators nicht, und es sieht so aus, als ob Alloc alloc = Alloc() Alloc = boost :: interprocess :: allocator verwendet wird und es keinen Standardkonstruktor hat. Es korreliert mit allen meinen Posts :-) Ich werde versuchen, meinen Code morgen, sehr herausforderndes Puzzle zu schreiben.

Ich habe Ihren Code geändert heute sehen Sie bitte unten und sehen, ob es Ihnen gefällt.

#include <boost/interprocess/managed_shared_memory.hpp> 
#include <boost/interprocess/allocators/allocator.hpp> 
#include <boost/interprocess/containers/vector.hpp> 
#include <boost/interprocess/containers/string.hpp> 
#include <boost/container/scoped_allocator.hpp> 
#include <iostream> 
#include <string> 
#include <sstream> 
#include <algorithm> 

namespace bip = boost::interprocess; 

namespace generic 
{ 

template <typename T, typename Alloc/* = std::allocator<T>*/ > 
using vector = bip::vector<T, typename Alloc::template rebind<T>::other >; 

template <typename Alloc/* = std::allocator<T>*/ > 
using GenericString = bip::basic_string<char, std::char_traits<char> 
          , typename Alloc::template rebind<char>::other>; 

template <typename Alloc> 
class String 
{ 
public: 
    typedef Alloc allocator_type; // ties in with uses_allocator/scoped_allocator 

    template<typename ...T> 
    String(const std::string &str, T && ...t) 
    : alloc_(std::forward<T>(t)...) , mString(str.c_str(), alloc_) 
    {} 

    template<typename ...T> 
    String(const char* str, T && ...t) 
    : alloc_(std::forward<T>(t)...) , mString(str, alloc_) 
    {} 

    template <typename OtherAlloc, typename ...T> 
    String(String<OtherAlloc> const& other, T && ...t) 
    : alloc_(std::forward<T>(t)...) , mString(other.mString.begin(), other.mString.end(), alloc_) 
    {} 

    std::string ToString() { return std::string(mString.begin(), mString.end()); } 

    friend std::ostream& operator<<(std::ostream& os, const String& str) 
    { 
    os << str.mString; 
    return os; 
    } 

private: 
    template<typename OtherAlloc> friend struct String; 
    Alloc alloc_; 
    GenericString<Alloc> mString; 
}; 

template <typename Alloc> 
class StringVector 
{ 
public: 
    typedef Alloc allocator_type; // ties in with uses_allocator/scoped_allocator 
    typedef vector<String<Alloc>, Alloc> GenericStringVector; 
    using Iterator = typename GenericStringVector::iterator; 
    using ConstIterator = typename GenericStringVector::const_iterator; 

    StringVector() 
    : alloc_(), mStrings(alloc_) 
    {} 

    template<typename T> 
    StringVector(T && t) 
    : alloc_(std::forward<T>(t)), mStrings(alloc_) 
    {} 

    template <typename OtherAlloc, typename ...T> 
    StringVector(StringVector<OtherAlloc> const& other, T && ...t) 
    : alloc_(std::forward<T>(t)...), mStrings(alloc_) 
    { 
     std::transform (other.mStrings.begin(), other.mStrings.end(), std::back_inserter(mStrings), [&t...](auto &s) { 
      return typename GenericStringVector::value_type(s, std::forward<T>(t)...); 
     }); 
    } 

    void Add(const String<Alloc> str) { mStrings.emplace_back(str); } 

    void Remove(Iterator iter) { mStrings.erase(iter); } 

    void Clear() { mStrings.clear(); } 

    void Print() const 
    { 
    std::cout << "["; 
    for (ConstIterator it = mStrings.begin(); it != mStrings.end(); it++) 
     std::cout << (it == mStrings.begin() ? "" : ", ") << *it; 
    std::cout << "]\n"; 
    } 

private: 
    template<typename OtherAlloc> friend struct StringVector; 
    Alloc alloc_; 
    GenericStringVector mStrings; 
}; 

} 

namespace heap 
{ 
    using VAlloc = std::allocator<void>; 
    using String = generic::String<VAlloc>; 
    using StringVector = generic::StringVector<VAlloc>; 
} 

namespace shared 
{ 
    using VAlloc =boost::container::scoped_allocator_adaptor< 
      bip::allocator<char, bip::managed_shared_memory::segment_manager> >; 

    using String = generic::String<VAlloc>; 
    using StringVector = generic::StringVector<VAlloc>; 
} 

int main(void) 
{ 
    struct shm_remove { 
     shm_remove() { bip::shared_memory_object::remove("MySharedMemory"); } 
     ~shm_remove() { bip::shared_memory_object::remove("MySharedMemory"); } 
    } remover; 

    std::cout << "Heap based storage: \n"; 
    heap::StringVector svec; 

    svec.Add(heap::String("test1")); 
    svec.Add(heap::String("test2")); 
    svec.Add(heap::String("test3")); 
    svec.Add(heap::String("test4")); 
    svec.Print(); 

    std::cout << "Shared memory storage: \n"; 
    bip::managed_shared_memory seg(bip::create_only, "MySharedMemory", 65536); 
    auto smp = seg.get_segment_manager(); 

    shared::StringVector sh_svec(smp); 
    sh_svec.Add(shared::String("test1", smp)); 
    sh_svec.Add(shared::String("test2", smp)); 
    sh_svec.Add(shared::String("test3", smp)); 
    sh_svec.Add(shared::String("test4", smp)); 
    sh_svec.Print(); 


    shared::StringVector sh_svec2(sh_svec, smp); 
    sh_svec2.Print(); 

    shared::StringVector sh_svec3(svec, smp); // does not give compile error 
    sh_svec3.Print(); 
} 
+0

ja. Ich habe eine Notwendigkeit, wo mein Code sowohl im Heapspeicher als auch im Shared-Memory-Speichersystem funktionieren muss. Daher versuche ich grundlegende Datenstrukturen zu finden, die mir dies ermöglichen. Danke, dass du dir die Zeit genommen hast. –

+0

Keine Sorge, ich habe Ihren generischen Code leicht neu berechnet, es kompiliert es läuft. –

+0

Das ist großartig. Vielen Dank. Ein letzter Gefallen. Könnten Sie bitte erläutern, was Sie im StringVector-Kopierkonstruktor getan haben? Was du getan hast, erscheint mir wie schwarze Magie. :) –

0

Sie hat keine Kompilierung Fehler jedoch nur durch einen kurzen Blick auf den Code und einige Arbeits wusste über boost::interprocess, ich glaube, Ihr Problem in std :: liegt Allokator verwendet für boost::interprocess, aber ich bin nicht 100% sicher, also bitte Kompilierungsfehler. wenn Sie In der Zwischenzeit gerne
Sie in unserem Open-Source-Stack Lösung für gemeinsam genutzte aussehen kann, Mmap, Haufen memory_types.hpp Ich glaube, Sie boost::interprocess::allocator mit boost::interprocess::managed_heap_memory::segment_manager oder etwas ähnliches verwenden können. Bitte geben Sie auch an, ob Sie C++ 03 oder C++ 11 Compiler verwenden, wie ich denke in C++ 03 war es typedef T* pointer_type und das wird nicht mit Boost Shared Memory arbeiten, da es offset_ptr, im Grunde vom Anfang des Speichers versetzt benötigt Segment und keine absolute Adresse.

ich geändert Code Ihnen geteilt :: StringVector benutzt hatte es kompiliert So, jetzt SHM Struktur zu speichern: denken

heap::StringVector sh_svec3(svec); // does not gives compile error :-) 
sh_svec3.Print(); 
+0

Die Kompilierungsfehler wurden hinzugefügt. Wollte die Frage nicht zu lang machen ... :( –

+0

Es kompiliert und verbindet für mich, ich benutze gcc 5.4 und boote 1,61 –

+0

Ich nehme an, dass Sie C++ 11 verwenden, weil sonst ** Vorlage mit ** würde nicht kompilieren, so ist die einzige Frage Ihre Boost-Version <1.58 –

Verwandte Themen