[Boost]::DI creating unique shared_ptr objects from injector - c++

Taking this sample code I'd like to have as a result that
button1 and button2 are two separate ojects.
#include <iostream>
#include <memory>
#include "di.hpp"
namespace di = boost::di;
struct CommandQueue {
void addCommand() {}
};
struct Control {
Control( CommandQueue &cq ) : cq( cq ) {
static int sid{};
id = ++sid;
}
CommandQueue& cq;
int id{};
};
int main() {
auto injector = di::make_injector( di::bind<CommandQueue>().in(di::singleton) );
auto button1 = injector.create<std::shared_ptr<Control>>();
auto button2 = injector.create<std::shared_ptr<Control>>();
std::cout << "button1->id = " << button1->id << std::endl;
std::cout << "button2->id = " << button2->id << std::endl;
return 0;
}
The current output is:
button1->id = 1
button2->id = 1
Instead of the intended:
button1->id = 1
button2->id = 2
Removing the di::singleton lifetime scope from CommandQueue singleton also doesn't fix it.
I know the lifetime scope for a shared_ptr is a singleton by default but I thought that was referred to the injected dependency not the actual object created with create.

Indeed the simplest thing could be
auto button1 = injector.create<Control>();
auto button2 = injector.create<Control>();
std::cout << "button1.id = " << button1.id() << std::endl;
std::cout << "button2.id = " << button2.id() << std::endl;
Prints
button1.id = 1
button2.id = 2
If you must have shared-pointers, the next simplest thing would be
auto button1 = std::make_shared<Control>(injector.create<Control>());
auto button2 = std::make_shared<Control>(injector.create<Control>());
std::cout << "button1->id = " << button1->id() << std::endl;
std::cout << "button2->id = " << button2->id() << std::endl;
Conceptually you want a control-factory, not a control. So, you should consider creating a factory from the dependency container:
#include <boost/di.hpp>
#include <iostream>
#include <memory>
namespace di = boost::di;
struct CommandQueue {
void addCommand() {}
};
struct Control {
Control(CommandQueue &cq) : _cq(cq), _id(idgen()) { }
int id() const { return _id; }
struct Factory {
Factory(CommandQueue& cq) : _cq(cq) {}
CommandQueue& _cq;
template <typename... Args>
auto operator()(Args&&... args) const {
return std::make_shared<Control>(_cq, std::forward<Args>(args)...);
}
};
private:
static int idgen() { static int sid{}; return ++sid; }
CommandQueue &_cq;
int _id{};
};
int main() {
auto injector = di::make_injector(di::bind<CommandQueue>().in(di::singleton));
auto factory = injector.create<Control::Factory>();
auto button1 = factory();
auto button2 = factory();
std::cout << "button1->id = " << button1->id() << std::endl;
std::cout << "button2->id = " << button2->id() << std::endl;
}

Related

std::remove_if() problem with the for looping

my code was
#include <iostream>
#include <list>
#include <functional>
using namespace std;
void tes(std::string s)
{
cout << "tes " << s << '\n';
}
void tes2(std::string s)
{
cout << "tes " << s << '\n';
}
void tes3(std::string s)
{
cout << "tes " << s << '\n';
}
int main()
{
using FuncType = std::function<void(std::string&)>;
std::list<std::pair<int, FuncType>> events =
{
{1, std::bind(tes, "1")},
{2, std::bind(tes2, "2")},
{3, std::bind(tes3, "3")} };
int t = 1;
auto remove_func = [&t](std::pair<int, FuncType> pair)
-> bool
{
return pair.first == t;
};
events.remove_if(remove_func);
for (auto ev : events)
{
std::cout << ev.first << ' ' ;
ev.second;
}
}
the result just display ev.first, but not the ev.second. what happened??
how to resolve this problem?? i mean display the string in FuncType function
such "2" and "3". or fixed this code properly to work to display each.
There are a couple of issues in the posted code
// ...
void tes(std::string s)
{ // ^^^^^^^^^^^^^
}
// ...
using FuncType = std::function<void(std::string&)>;
// ^^^^^^^^^^^^
std::list<std::pair<int, FuncType>> events =
{
{1, std::bind(tes, "1")},
{2, std::bind(tes2, "2")},
{3, std::bind(tes3, "3")}
// ^^^^^^^^^^^^^^^^^^^^
};
The functions like tes have one parameter of type std::string, the alias FuncType is a std::function with one parameter of type std::string&, but the pairs in events are assigned the results of std::bind, which have zero parameters (they are, well, binded).
Moreover, in the printing loop
for (auto ev : events)
{
std::cout << ev.first << ' ' ;
ev.second; // <- This does nothing, it should be a call.
}
The fix1 is straightforward:
using FuncType = std::function<void(void)>;
// ^^^^^^
// ...
for (auto ev : events)
{
std::cout << ev.first << ' ' ;
ev.second();
// ^^
}
1) https://godbolt.org/z/5f8srj9va
Fix the misprint:
std::cout << ev.first << ' ' << ev.second;

Pass constructor arguments to member object

I am sure this question has been answered before, but I am unable to find a satisfactory answer. Take the following example:
class A {
public:
A(int a, int b, int c);
//...
};
class B {
public:
B(...);
private:
A _a0;
A _a1;
A _a2;
A _a3;
};
Class B contains multiple instances of class A. I want to represent that B "owns" all of these instances. From what I know, there are a couple ways to represent this
The instances of A are declare as direct members of B (as I have shown), and thus the memory of the A instances is directly inside the B class.
B contains a bunch of unique_ptr objects to the A classes
Use the Builder design pattern to do the creation on step at a time
The reason I don't want to use (2) and (3) is that I want NO heap allocation of these objects (I am writing for an embedded system).
The problem with (1) is, since each A requires 3 constructor parameters and these parameters are not provided by B but rather by the application writer (i.e., B merely owns and uses these instances of A but does not need to know how to create them), I have the bad option of passing 12 arguments to the constructor of B in order to create all 4 As.
I am wondering if another option would be to write the constructor of B such that it takes r-values to As and then move these As into B?
For example:
class B {
public:
B(A&& a0, A&& a1, A&& a2, A&& a3) :
_a0(std::move(a0)),
_a1(std::move(a1)),
_a2(std::move(a2)),
_a3(std::move(a3))
{
}
private:
A _a0;
A _a1;
A _a2;
A _a3;
};
The one problem I can see which this solution is, what if A is a class which points/refers to some "global" resource. The constructor of A should initialize this resource and the destructor should de-initialize this resource. If A is moved, the reference/pointer to the resource also has to be moved AND the old copy of A has to be placed in some valid state which does not de-initialize the resource because ownership has been transferred. What would be the correct way to represent this?
So, your main problem is designing class A. From your description looks like it should be non-copyable, but move-constructible (and move-assignable):
The one problem I can see which this solution is, what if A is a class
which points/refers to some "global" resource. The constructor of A
should initialize this resource and the destructor should
de-initialize this resource. If A is moved, the reference/pointer to
the resource also has to be moved AND the old copy of A has to be
placed in some valid state which does not de-initialize the resource
because ownership has been transferred.
The usual way to create such a class is by using unique_ptr with a custom deleter. Suppose, you have class Resource and
Resource* init_resource(int a);
void deinit_resource(Resource*);
Then, your class A may look like:
class A {
public:
A(int a, int b, int c)
: r( init_resource(a) )
{
//...
}
private:
std::unique_ptr<Resource, deinit_resource> r;
//...
};
With this class A, your constructor design of class B will work, but this is not the only way. If you like Builder pattern but cannot use dynamic memory, then std::optional is your friend. For example:
class B
{
public:
B(){}
void set_A1(int a, int b, int c)
{
a1_ = A(a, b, c);
}
//...
private:
std::optional<A> a1_;
//...
};
Here is a solution I put together that seems to work correctly
#include <assert.h>
#include <utility>
#include <cstdint>
#include <iostream>
#include <atomic>
/*
* Some global resource
* On an embedded system, this would be the peripherals/special-purpose registers
*/
static unsigned int resource1 = 0;
static unsigned int resource2 = 0;
/*
* Often, an SDK for an MCU will provide #define statements which contain the
* the start address (as an integer) of the peripheral register(s)
*/
#define RESOURCE1_ADDR (std::intptr_t)(&resource1)
#define RESOURCE2_ADDR (std::intptr_t)(&resource2)
template <typename T>
class ResourceManager;
/**
* #brief A handle to a particular resource managed by a ResourceManager
* #note Similar to unique_ptr, a ResourceHandle may only be moved
*/
template <typename T>
class ResourceHandle {
public:
~ResourceHandle() {
std::cout << "ResourceHandle::~ResourceHandle()" << std::endl;
}
/**
* #brief Helper method to release the resource managed by this handle back
* to its appropriate resource manager.
*/
inline void release() {
assert(_addr != 0);
_manager.release(std::move(*this));
}
/**
* #brief Copy constructor
* #note Deleted because ResourceHandle is move-only
*/
ResourceHandle(const ResourceHandle& other) = delete;
/**
* #brief Assignment operator
* #note Deleted because ResourceHandle is move-only
*/
const ResourceHandle& operator=(const ResourceHandle&) = delete;
ResourceHandle(ResourceHandle&& other) :
_manager(other._manager),
_addr(other._addr)
{
std::cout << "ResourceHandle::ResourceHandle(ResourceHandle&&)" << std::endl;
assert(_addr != 0);
other._addr = 0;
}
ResourceHandle& operator=(ResourceHandle&& other) {
std::cout << "ResourceHandle::operator=(ResourceHandle&&)" << std::endl;
if (this != &other) {
_addr = other._addr;
other._addr = 0;
}
return *this;
}
operator T*() const {
assert(_addr != 0);
return reinterpret_cast<T*>(_addr);
}
T* operator->() const { return operator T*(); }
inline bool isValid() const { return _addr != 0; }
protected:
ResourceHandle(ResourceManager<T>& manager, std::intptr_t addr) :
_manager(manager),
_addr(addr)
{
std::cout << "ResourceHandle::ResourceHandle(ResourceManager<T>&, std::intptr_t)" << std::endl;
}
private:
ResourceManager<T>& _manager;
/**
* #brief The integer address of the resource being mamaged by this handle
* #note Set to 0 when invalid
*/
std::intptr_t _addr;
friend class ResourceManager<T>;
};
/**
* #brief Class which manages a particular resource by allowing a ResourceHandle
* to be "obtained" and "released"
*/
template <typename T>
class ResourceManager {
public:
constexpr ResourceManager(std::intptr_t addr) :
_resource(*this, addr)
{
}
constexpr ResourceHandle<T> obtain() {
std::cout << "ResourceHandle::obtain()" << std::endl;
assert(_resource.isValid());
return std::move(_resource);
}
constexpr void release(ResourceHandle<T> r) {
std::cout << "ResourceHandle::release()" << std::endl;
assert(!_resource.isValid());
_resource = std::move(r);
}
private:
ResourceHandle<T> _resource;
};
/**
* #brief Example class which "uses" (i.e., takes ownership of) a resource
* via a ResourceHandle
*/
class ResourceUser {
public:
ResourceUser(ResourceHandle<unsigned int> r) :
_r(std::move(r))
{
std::cout << "ResourceUser::ResourceUser(ResourceHandle<unsigned int>)" << std::endl;
//Init
std::cout << "ResourceUser -> Init resource" << std::endl;
*_r = 0;
}
~ResourceUser() {
std::cout << "ResourceUser::~ResourceUser()" << std::endl;
if (_r.isValid()) {
std::cout << "ResourceUser -> Cleanup resource" << std::endl;
*_r = 0;
_r.release();
}
}
ResourceUser(ResourceUser&& other) :
_r(std::move(other._r))
{
std::cout << "ResourceUser::ResourceUser(ResourceUser&&)" << std::endl;
}
void set(unsigned int x) {
std::cout << "ResourceUser::set()" << std::endl;
*_r = x;
}
private:
ResourceHandle<unsigned int> _r;
};
/**
* #brief Example class which "owns" two ResourceUser objects
*/
class ResourceUserUser {
public:
ResourceUserUser(ResourceUser&& a, ResourceUser&& b) :
_a(std::move(a)),
_b(std::move(b))
{
std::cout << "ResourceUserUser::ResourceUserUser()" << std::endl;
}
~ResourceUserUser() {
std::cout << "ResourceUserUser::~ResourceUserUser()" << std::endl;
}
void foo() {
std::cout << "ResourceUserUser::foo()" << std::endl;
_a.set(10);
_b.set(20);
}
private:
ResourceUser _a;
ResourceUser _b;
};
class Resource1 : public ResourceManager<unsigned int> {
public:
inline static ResourceManager<unsigned int>& instance() { return _instance; }
private:
static ResourceManager<unsigned int> _instance;
};
class Resource2 : public ResourceManager<unsigned int> {
public:
inline static ResourceManager<unsigned int>& instance() { return _instance; }
private:
static ResourceManager<unsigned int> _instance;
};
ResourceManager<unsigned int> Resource1::_instance(RESOURCE1_ADDR);
ResourceManager<unsigned int> Resource2::_instance(RESOURCE2_ADDR);
void test1() {
std::cout << std::endl << "BEGIN test1()" << std::endl;
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
ResourceUser user(Resource1::instance().obtain());
user.set(20);
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
std::cout << "END test1()" << std::endl;
}
void test2() {
std::cout << std::endl << "BEGIN test2()" << std::endl;
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
ResourceUserUser user(ResourceUser{Resource1::instance().obtain()}, ResourceUser{Resource2::instance().obtain()});
user.foo();
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
std::cout << "END test2()" << std::endl;
}
void test3() {
std::cout << std::endl << "BEGIN test3()" << std::endl;
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
ResourceUser user1(Resource1::instance().obtain());
ResourceUserUser user2(ResourceUser{Resource1::instance().obtain()}, ResourceUser{Resource2::instance().obtain()});
user2.foo();
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
std::cout << "END test3()" << std::endl;
}
If you execute test2() the output is
ResourceHandle::ResourceHandle(ResourceManager<T>&, std::intptr_t)
ResourceHandle::ResourceHandle(ResourceManager<T>&, std::intptr_t)
BEGIN test2()
resource1 = 0
resource2 = 0
ResourceHandle::obtain()
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceHandle<unsigned int>)
ResourceUser -> Init resource
ResourceHandle::obtain()
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceHandle<unsigned int>)
ResourceUser -> Init resource
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceUser&&)
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceUser&&)
ResourceUserUser::ResourceUserUser()
ResourceUser::~ResourceUser()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceUser::~ResourceUser()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceUserUser::foo()
ResourceUser::set()
ResourceUser::set()
resource1 = 10
resource2 = 20
END test2()
ResourceUserUser::~ResourceUserUser()
ResourceUser::~ResourceUser()
ResourceUser -> Cleanup resource
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::release()
ResourceHandle::operator=(ResourceHandle&&)
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceUser::~ResourceUser()
ResourceUser -> Cleanup resource
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::release()
ResourceHandle::operator=(ResourceHandle&&)
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
I am curious though, is there any way I can get rid of those extra calls to the move constructor? For example, the ResourceManager calls the move constructor to move the handle out of itself, then the ResourceUser calls the move constructor again.

C++ : custom vtable implementation does not work

I'm trying to implement a custom vtable to better understand a concept of virtual tables and overriding. For this I have the following 'base' class
#pragma once
#include <iostream>
#include <string>
using namespace std::string_view_literals;
struct vtable;
class IdentityDocument {
public:
IdentityDocument()
: vtable_ptr_(&IdentityDocument::VTABLE),
unique_id_(++unique_id_count_)
{
std::cout << "IdentityDocument::Ctor() : "sv << unique_id_ << std::endl;
}
~IdentityDocument() {
--unique_id_count_;
std::cout << "IdentityDocument::Dtor() : "sv << unique_id_ << std::endl;
}
IdentityDocument(const IdentityDocument& other)
: vtable_ptr_(other.vtable_ptr_),
unique_id_(++unique_id_count_)
{
std::cout << "IdentityDocument::CCtor() : "sv << unique_id_ << std::endl;
}
IdentityDocument& operator=(const IdentityDocument&) = delete;
void PrintID() const {
std::cout << "IdentityDocument::PrintID() : "sv << unique_id_ << std::endl;
}
static void PrintUniqueIDCount() {
std::cout << "unique_id_count_ : "sv << unique_id_count_ << std::endl;
}
int GetID() const {
return unique_id_;
}
private:
vtable* vtable_ptr_ = nullptr;
static int unique_id_count_;
static vtable VTABLE;
int unique_id_;
};
struct vtable
{
void (IdentityDocument::* const PrintID)() const;
vtable (
void (IdentityDocument::* const PrintID)() const
) : PrintID(PrintID) {}
};
int IdentityDocument::unique_id_count_ = 0;
vtable IdentityDocument::VTABLE = {&IdentityDocument::PrintID};
And here is another class that must override PrintId method
#pragma once
#include "identity_document.h"
#include <iostream>
#include <string>
#include <ctime>
using namespace std::string_view_literals;
class Passport {
public:
Passport()
: expiration_date_(GetExpirationDate())
{
IdentityDocument* base_ptr = reinterpret_cast<IdentityDocument*>(this);
vtable* vtable_ptr = reinterpret_cast<vtable*>(base_ptr);
vtable_ptr = &Passport::VTABLE;
std::cout << "Passport::Ctor()"sv << std::endl;
}
Passport(const Passport& other)
: identity_(other.identity_)
, expiration_date_(other.expiration_date_)
{
IdentityDocument* base_ptr = reinterpret_cast<IdentityDocument*>(this);
vtable* vtable_ptr = reinterpret_cast<vtable*>(base_ptr);
vtable_ptr = &Passport::VTABLE;
std::cout << "Passport::CCtor()"sv << std::endl;
}
~Passport() {
std::cout << "Passport::Dtor()"sv << std::endl;
}
void PrintID() const {
std::cout << "Passport::PrintID() : "sv << identity_.GetID();
std::cout << " expiration date : "sv << expiration_date_.tm_mday << "/"sv << expiration_date_.tm_mon << "/"sv
<< expiration_date_.tm_year + 1900 << std::endl;
}
void PrintVisa(const std::string& country) const {
std::cout << "Passport::PrintVisa("sv << country << ") : "sv << identity_.GetID() << std::endl;
}
private:
IdentityDocument identity_;
const struct tm expiration_date_;
static vtable VTABLE;
tm GetExpirationDate() {
time_t t = time(nullptr);
tm exp_date = *localtime(&t);
exp_date.tm_year += 10;
mktime(&exp_date);
return exp_date;
}
};
vtable Passport::VTABLE = {reinterpret_cast<void (IdentityDocument::*)() const>(&Passport::PrintID)};
And a short demo :
int main() {
array<IdentityDocument*, 1> docs = { (IdentityDocument*)(new Passport()) };
for (const auto* doc : docs) {
doc->PrintID();
}
}
Unfortunately, I see that the 'derived' method was not called. Am I using a wrong approach to implement a vtable concept?
Am I using a wrong approach to implement a vtable concept?
Yes. You have not written any code that reads your vtable, and the C++ compiler will not generate any code to read your vtable either.
When you declare a member function virtual, your compiler needs to call that function in a special way. Any call to that function should be looked up in a vtable.
When a member function is not virtual, your compiler knows that it doesn't need to look up the location of the function. It knows which function to call. No lookup needed.
In your code, you have created a vtable, but this line, calling a non-virtual function:
doc->PrintID();
Does not need a vtable, and does not check for one.
doc is an IdentityDocument*, so doc->PrintID() calls IdentityDocument::PrintID(). No lookup required, no lookup happens.
Finally I simplified my solution and got what I wanted :
#include <iostream>
class A;
struct VTable
{
void (*say_hello)(A*);
};
class A
{
public:
A()
{
vtable.say_hello = A::sayHello;
}
void sayHello()
{
vtable.say_hello(this);
}
static void sayHello(A* a)
{
std::cout << "A::sayHello" << std::endl;
}
VTable vtable;
};
class B
{
public:
B()
{
a.vtable.say_hello = B::sayHello;
}
void sayHello()
{
a.vtable.say_hello((A*)this);
}
static void sayHello(A* a)
{
std::cout << "B::sayHello\n" << std::endl;
}
private:
A a;
};
int main()
{
A* a = (A*)(new B);
a->sayHello();
delete a;
}

How to prevent compilation of passed lambda, if arguments are not references

In one of my projects I'm using a small utility function, which takes a Message struct and a lambda function, that modifies this message struct.
Now, I unintentionally passed a lambda without the necessary reference &. It perfectly compiles, but doesn't gave the desired output.
As for me, there should be one of the two following behaviors:
Forgetting to write auto&, but just auto should lead to compilation errors
Writing just auto should be interpreted as auto&.
It is possible to prevent compilation in case of a missing & or even better to interpret auto as auto& automatically?
#include <iostream>
#include <functional>
#include <boost/variant.hpp>
struct Message {
int x;
int y;
};
void changeMessage(Message& m, const std::function<void(Message&)>& messageModifier) {
std::cout << "Message before:" << m.x << " " << m.y << "\n";
messageModifier(m);
std::cout << "Message after:" << m.x << " " << m.y << "\n";
}
int main(int, char**) {
{
std::function<void(int&)> f = [](int&) {};
std::function<void(int)> g = [](int) {};
f = g; // This compiles.
}
{
std::function<void(int&)> f = [](int&) {};
std::function<void(int)> g = [](int) {};
//g = f; // This does not compile. Makes perfect sense.
}
Message m{ 10,20 };
{
changeMessage(m, [](auto m) { m.x++; m.y--; }); // User unintentionally forgot &! Can I prevent this from compilation?
std::cout << "Message outside: " << m.x << " " << m.y << "\n";
}
{
changeMessage(m, [](auto& m) { m.x++; m.y--; });
std::cout << "Message outside: " << m.x << " " << m.y << "\n";
}
}
One way to prevent passing Message by value (and auto itself is never a reference) is to disable copy construction:
struct Message {
Message() = default;
Message(const Message&) = delete;
int x;
int y;
};
Another solution suggested by #L. F. is to check that lambda doesn't accept rvalues:
template<class Fn>
void change_message(Message& m, Fn fn) {
static_assert(!std::is_invocable_v<Fn, Message&&>);
fn(m);
}

constructing object with private constructor inside boost managed_memory_segment

I have a class like below:
class X {
public:
static X *factory(...);
static void destroy(X *x);
private:
X();
~X();
};
I am trying to construct this object in shared memory using boost managed_shared_memory following the examples in
http://www.boost.org/doc/libs/1_47_0/doc/html/interprocess/managed_memory_segments.html#interprocess.managed_memory_segments.managed_memory_segment_features.allocation_types
How do I use find_or_construct() or construct() in this case given that the constructor is private ? Are we forced make the constructors public and not use factory/destroy methods for the classes being constructed in shared memory ?
Thanks,
S.K
You can simply pass a reference to the segment manager (or an associated allocator, depending on your requirements).
Often you'll require the allocator anyways for any embedded objects that use them.
Live On Coliru
#include <boost/interprocess/allocators/allocator.hpp>
namespace bip = boost::interprocess;
class X {
public:
template <typename SegmentManager>
static X* factory(int id, SegmentManager* sm) {
bip::allocator<X, SegmentManager> alloc{sm};
X* x = alloc.allocate(1).get();
new (x) X(id);
return x;
}
template <typename SegmentManager>
static void destroy(X *x, SegmentManager* sm) {
if (!x) return;
bip::allocator<X, SegmentManager> alloc{sm};
x->~X();
alloc.deallocate(x, 1);
}
int getId() const { return id; }
private:
X(int id) : id(id) {}
~X() = default;
int id;
};
#include <iostream>
template <typename Segment>
void run_test(Segment& segment) {
std::cout << "Free: " << segment.get_free_memory() << '\n';
auto sm = segment.get_segment_manager();
auto a = X::factory(42, sm);
auto b = X::factory(43, sm);
std::cout << "Free: " << segment.get_free_memory() << '\n';
X& aref = *a;
std::cout << "a.id = " << aref.getId() << "\n";
std::cout << "b.id = " << b->getId() << "\n";
X::destroy(a, sm);
X::destroy(b, sm);
std::cout << "Free: " << segment.get_free_memory() << '\n';
}
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
int main() {
bip::managed_mapped_file mmf(bip::open_or_create, "test.bin", 10240);
bip::managed_shared_memory msm(bip::open_or_create, "MySharedMemory", 10240);
std::cout << " ------------- managed_mapped_file ---------------\n";
run_test(mmf);
std::cout << " ------------- managed_shared_memory -------------\n";
run_test(msm);
}
Prints:
------------- managed_mapped_file ---------------
Free: 10016
Free: 9920
a.id = 42
b.id = 43
Free: 10016
------------- managed_shared_memory -------------
Free: 10016
Free: 9920
a.id = 42
b.id = 43
Free: 10016