How can I get a string from an extended shared memory vector without triggering a shared memory allocation from the recovered string constructor?
given these types (from here , more or less):
typedef boost::interprocess::managed_shared_memory::segment_manager SegmentManager;
typedef boost::interprocess::allocator<char, SegmentManager> CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> ShmString;
typedef boost::interprocess::allocator<ShmString, SegmentManager> StringAllocator;
typedef boost::interprocess::vector<ShmString, StringAllocator> ShmStringVector;
Whenever I retrieve the ShmString from ShmStringVector
, the free size of the shared memory segment decreases.
What I think happens whenever it ShmString
is created, even as a stack variable, it allocates space inside the shared memory segment.
When this one ShmString
goes out of scope, memory is returned. But if I'm close to capacity on my segment, I don't want the access to risk causing overruns on the shared memory segment.
How can I get the string without triggering another selection?
In the example below, I tried
//shared mem segment previously created with 1,000,000 bytes allocated
managed_shared_memory segment(open_only, "somename");
CharAllocator charAllocator(segment.get_segment_manager());
ShmStringVector *vec = segment.find<ShmStringVector>("somevectorname").first;
vec->push_back(" ... big string ..." ); // I can push a const char*
size_t sizeAfterInsertion = segment.get_free_memory();
ShmString res1 = vec->at(0); //works, but steals memory from shared memory, at least temporarily !
const char* res2 = vec->at(0); //compiler error
std::string res3 = vec->at(0); //compiler error
size_t sizeAfterGet = segment2.get_free_memory();
size_t diff = sizeAfterInsertion - sizeAfterGet;
I proved that memory is taken by declaring ShmString
...
std::string size 170,
before ins: 999232, after ins: 998976, shared memory taken by ins: 256
after get: 998768, shared memory taken by get: 208
source to share
As Wug mentions, you can use the link.
Conversion / assignment between string types:
If you really want a copy outside of shared memory, copy it to a regular string (or other allocator):
std::string copied(vec2->at(0).begin(), vec2->at(0).end());
Of course, the same works in reverse:
vec2[0].assign(copied.begin(), copied.end());
// Or
vec2->emplace_back({copied.begin(), copied.end()});
and etc.
Using Streams Directly in Shared Memory
Note that there is streaming support for Interprocess:
typedef allocator<int, managed_shared_memory::segment_manager>
IntAllocator;
typedef allocator<char, managed_shared_memory::segment_manager>
CharAllocator;
typedef vector<int, IntAllocator> MyVector;
typedef basic_string
<char, std::char_traits<char>, CharAllocator> MyString;
typedef basic_vectorstream<MyString> MyStringStream;
Now you can use MyVectorStream
to read / write to shared memory string. This is similar to std::stringstream
, but without having to copy the data to the stream first.
For example, write some data into a vector:
//Create the stream. To create the internal shared memory
//basic_string we need to pass the shared memory allocator as
//a constructor argument
MyStringStream mystringstream(CharAllocator(segment.get_segment_manager()));
//Reserve the internal string
mystringstream.reserve(100*5);
//Write all vector elements as text in the internal string
//Data will be directly written in shared memory, because
//internal string allocator is a shared memory allocator
for(std::size_t i = 0, max = myvector->size(); i < max; ++i){
mystringstream << (*myvector)[i] << std::endl;
}
And read it to copy it directly to another shared memory line:
//Auxiliary vector to compare original data
MyVector *myvector2 =
segment.construct<MyVector>("MyVector2")
(IntAllocator(segment.get_segment_manager()));
//Avoid reallocations
myvector2->reserve(100);
//Extract all values from the internal
//string directly to a shared memory vector.
std::istream_iterator<int> it(mystringstream), itend;
std::copy(it, itend, std::back_inserter(*myvector2));
//Compare vectors
assert(std::equal(myvector->begin(), myvector->end(), myvector2->begin()));
This is taken from the sample documentation and you can see it [ Live On Coliru] ( http://coliru.stacked-crooked.com/a/7f1f450ac11edd4a
source to share