1

Recently I got schooled and learnt the proper way of having a unordered_map inside a boost::interprocess::managed_shared_memory segment. So far so good, but I will need to add a few more STL containers.

Ideally, I would want to be able to follow the same for any STL container. Right now I'm in need of a std::list. I can't make it work. I can make a std::vector work, though.

std::vector

The following code works:

#include <vector>
#include <boost/interprocess/managed_shared_memory.hpp>

namespace ipc = boost::interprocess;
using Segment = ipc::managed_shared_memory;
using Manager = Segment::segment_manager;
template <typename T> using Alloc = ipc::allocator<T, Manager>;
template <typename K> using Vector = std::vector<K, Alloc<K>>;

int main() {
  boost::interprocess::shared_memory_object::remove("test");
  Segment _segment{ipc::create_only, "test", 1ul<<40};
  Manager *mgr = _segment.get_segment_manager();
  Vector<int> *v = _segment.construct<Vector<int>>("v")(mgr);
  v->emplace_back(1);
}

std::list

The list-equivalent code results in an error.

#include <list>
#include <boost/interprocess/managed_shared_memory.hpp>

namespace ipc = boost::interprocess;
using Segment = ipc::managed_shared_memory;
using Manager = Segment::segment_manager;
template <typename T> using Alloc = ipc::allocator<T, Manager>;
template <typename K> using List = std::list<K, Alloc<K>>;

int main() {
  boost::interprocess::shared_memory_object::remove("test");
  Segment _segment{ipc::create_only, "test", 1ul<<40};
  Manager *mgr = _segment.get_segment_manager();
  List<int> *v = _segment.construct<List<int>>("v")(mgr);
  v->emplace_back(1);
}

The compilation flags (using g++-7) and error are the following:

$ g++ -std=gnu++17 lol_list.cpp -lrt -pthread -rdynamic -Wfatal-errors && ./a.out && rm ./a.out
In file included from /usr/include/c++/7/list:63:0,
                 from lol_list.cpp:1:
/usr/include/c++/7/bits/stl_list.h: In instantiation of ‘std::__cxx11::list<_Tp, _Alloc>::_Node* std::__cxx11::list<_Tp, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {int}; _Tp = int; _Alloc = boost::interprocess::allocator<int, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> >; std::__cxx11::list<_Tp, _Alloc>::_Node = std::_List_node<int>]’:
/usr/include/c++/7/bits/stl_list.h:1801:32:   required from ‘void std::__cxx11::list<_Tp, _Alloc>::_M_insert(std::__cxx11::list<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {int}; _Tp = int; _Alloc = boost::interprocess::allocator<int, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> >; std::__cxx11::list<_Tp, _Alloc>::iterator = std::_List_iterator<int>]’
/usr/include/c++/7/bits/stl_list.h:1133:4:   required from ‘std::__cxx11::list<_Tp, _Alloc>::reference std::__cxx11::list<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {int}; _Tp = int; _Alloc = boost::interprocess::allocator<int, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> >; std::__cxx11::list<_Tp, _Alloc>::reference = int&]’
lol_list.cpp:16:20:   required from here
/usr/include/c++/7/bits/stl_list.h:578:11: error: cannot convert ‘boost::interprocess::offset_ptr<std::_List_node<int>, long int, long unsigned int, 0>’ to ‘std::__cxx11::list<int, boost::interprocess::allocator<int, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > >::_Node* {aka std::_List_node<int>*}’ in return
    return __p;
           ^~~
compilation terminated due to -Wfatal-errors.

The error persists with g++-6 or g++-8 and even with clang-6.0 and clang-5.0.

2 Answers 2

2

Not all standard library implementations fully support stateful allocators (yet?).

In this case it appears that your std::list<> doesn't. Simply opt for the one for Boost Container, which is conveniently also available through Boost Interprocess headers:

#include <boost/interprocess/containers/list.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>

namespace ipc = boost::interprocess;
using Segment = ipc::managed_shared_memory;
using Manager = Segment::segment_manager;
template <typename T> using Alloc = ipc::allocator<T, Manager>;
template <typename K> using List = ipc::list<K, Alloc<K>>;

int main() {
    boost::interprocess::shared_memory_object::remove("test");
    Segment _segment{ipc::create_only, "test", 1ul<<40};
    Manager *mgr = _segment.get_segment_manager();
    List<int> *v = _segment.construct<List<int>>("v")(mgr);
    v->emplace_back(1);
}
Sign up to request clarification or add additional context in comments.

7 Comments

This is a bit ironic, as per yesterday's comments on your std::unordered_map answer. This solution works -- compiles and inserts properly.
No problem. Thanks for posting the other self-answered question, upvoted that just now :)
Do they claim it across the board? If they claim it for one container but not the other, it's not a bug. Perhaps there is a "feature readiness" page that makes the promises more explicit. Is not that plausible that they'd skip the feature "untested"
By the way, another frequent hurdle is the use of non-raw pointer types (so when allocator <T>::pointer_type != T*)
As the comment above this one says, the problem is not lack of support for stateful allocators, it's lack of support for "fancy pointers" and there's already a bug report: gcc.gnu.org/bugzilla/show_bug.cgi?id=57272
|
1

[allocator.requirements] paragraph 9:

An allocator may constrain the types on which it can be instantiated and the arguments for which its construct member may be called. If a type cannot be used with a particular allocator, the allocator class or the call to construct may fail to instantiate.

It's OK for your allocator to refuse to allocate memory for anything except a T. That will prevent it being used in node-based containers such as std::list which need to allocate their own internal node types (not just the container's value_type) but it will work fine for std::vector

As posted in https://stackoverflow.com/a/28995278/4288486 by @Jonathan-Wakely

1 Comment

That's not the problem here though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.