Hello,
we would like to store collections of differents objects derived from a same base class in a shared
memory segment, and use polymorphism to manipulate them using shared_ptr<base>.
But as we can't have virtual functions in shared memory we are exploring this solution :
We designed 2 parallels hierarchies of classes
- A hierarchy of empty objects in process memory with virtual functions (polymorphism) (ex : class A)
- A hierarchy of data objects in shared memory without virtual functions (class A_data)
A "process memory" object stores a weak_ptr to the "shared memory" data object.
Use of data are encapsuled in accessors which take care of weak_ptr locking and concurrent access.
I don't know if this is a good design (any opinions ?) but it seems to work well... until the destruction
of "shared memory" objects.
The wrong destructor is used (the base one) instead of the destructor of the derived class,
probably because the destructor is not virtual...
So I'm currently stuck and I'm looking for some advices.
Here is a little code demonstrating the problem :
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
#include <iostream>
using namespace boost::interprocess;
using namespace std;
class base {
protected :
int id;
public:
base(int i=0):id(i){};
~base(){cout << "base dtor" << endl;}
int getId() const {return id;}
};
class derived : public base {
protected:
double data;
public:
derived(int i=0, double d=0): base(i), data(d){};
~derived(){cout << "derived dtor" << endl;}
double getData(){return data;}
};
typedef managed_shared_ptr<base, fixed_managed_shared_memory>::type base_shared_ptr;
int main (){
fixed_managed_shared_memory segment(open_or_create,"sharedPtrSharedMemoryTest", 2048);
// does not compile but that's what I would like
//base_shared_ptr baseSP = make_managed_shared_ptr(segment.construct<derived>(anonymous_instance)(2,3.0), segment);
// turnaround
base_shared_ptr baseSP = make_managed_shared_ptr((base*)segment.construct<derived>(anonymous_instance)(2,3.0), segment);
cout << "baseSP->getId() =" << baseSP->getId();
cout <<", baseSP->getData() = " << static_pointer_cast<derived>(baseSP)->getData() << endl;
baseSP.reset(); // don't know why but base dtor is called 3 times !!!
}
I can live with static_pointer_cast<> because they'll be hidden in accessors.
But I really need that the right destructor (here ~derived()) will be called as it's cause some asserts in real case :
include/boost/interprocess/detail/segment_manager_helper.hpp:176: static boost::interprocess::detail::block_header* boost::interprocess::detail::block_header::block_header_from_value(const void*, size_t, size_t): Assertion `hdr->m_value_alignment == algn' failed.
The commented call to make_managed_shared_ptr makes gcc complains with (thanks gfilt for formatting) :
sharedPtrSharedMemoryTest.cc:30: error: conversion from
`boost::interprocess::shared_ptr<
derived
, boost::interprocess::allocator<
void
, boost::interprocess::segment_manager<
char
, boost::interprocess::rbtree_best_fit<
boost::interprocess::mutex_family, void *, 0u
>, boost::interprocess::iset_index
>
>, boost::interprocess::deleter<
derived
, boost::interprocess::segment_manager<
char
, boost::interprocess::rbtree_best_fit<
boost::interprocess::mutex_family, void *, 0u
>, boost::interprocess::iset_index
> > >' to non-scalar type
`boost::interprocess::shared_ptr<
base
, boost::interprocess::allocator<
void
, boost::interprocess::segment_manager<
char
, boost::interprocess::rbtree_best_fit<
boost::interprocess::mutex_family, void *, 0u
>, boost::interprocess::iset_index
>
>, boost::interprocess::deleter<
base
, boost::interprocess::segment_manager<
char
, boost::interprocess::rbtree_best_fit<
boost::interprocess::mutex_family, void *, 0u
>, boost::interprocess::iset_index
>
>
>' requested
Any help will be welcome.
Gaetan