При создании общей памяти и памяти картированных файлов для передачи двух процессов сегмент памяти может быть отображен по другому адресу в каждом процессе:
#include<boost/interprocess/shared_memory_object.hpp>
using boost::interprocess;
shared_memory_object shm_obj
(open_only
,"shared_memory"
,read_only
);
mapped_region region
( shm
, read_write
);
void *addr = region.get_address();
Это затрудняет создание сложных объектов в картированных регионах: экземпляр класса C++, помещенный в картированную область, может иметь указатель, указывающий на другой объект, также расположенный в картографической области. Поскольку указатель сохраняет абсолютный адрес, этот адрес действителен только для процесса, который поместил объект там, если все процессы не отображают на карте область в одном и том же адресе.
Чтобы иметь возможность имитировать указатели в картированных регионах, пользователи должны использовать offsets (расстояние между объектами) вместо абсолютных адресов. Компенсация между двумя объектами в обозначенной области одинакова для любого процесса, который отображает отображенную область, даже если этот регион помещен в разные базовые адреса. Для облегчения использования офсетов Boost.Interprocess предлагает offset_ptr.
offset_ptr
обертывает все фоновые операции, необходимые для создания точечного интерфейса. Интерфейс класса вдохновлен в Boost Smart Pointers, и этот умный указатель сохраняет смещение (расстояние в байтах) между адресом указателя и собственным этим
указателем. Представьте структуру в общем 32-битном процессоре:
struct structure
{
int integer1;
offset_ptr<int> ptr;
int integer2;
};
structure s;
s.ptr = &s.integer1;
s.ptr = &s.integer2;
Одной из больших проблем offset_ptr
является представление нулевого указателя. Нулевой указатель не может быть безопасно представлен как офсет, поскольку абсолютный адрес 0 всегда находится за пределами обозначенной области. Из-за того, что сегмент может быть отображен по другому базовому адресу в каждом процессе, расстояние между адресом 0 и offset_ptr
разное для каждого процесса.
Некоторые реализации выбирают офсет 0 (то есть offset_ptr
указывая на себя) в качестве нулевого указателя указателя, но это не актуально для многих случаев использования, поскольку много раз структуры, такие как связанные списки или узлы из контейнеров STL указывают на себя (конечный узел в пустом контейнере, например) и 0 офсетное значение необходимо. Альтернатива состоит в том, чтобы хранить, в дополнение к офсету, булеан, чтобы указать, является ли указатель нулевым. Однако это увеличивает размер указателя и вредит производительности.
Следовательно, offset_ptr
определяет офсет 1 как нуль-указатель, что означает, что этот класс не может указать на байт после своего это указателя:
using namespace boost::interprocess;
offset_ptr<char> ptr;
ptr = (char*)&ptr + 1;
assert(!ptr);
ptr = 0;
assert(!ptr);
На практике это ограничение не важно, поскольку пользователь почти никогда не хочет указывать на этот адрес.
offset_ptr
предлагает все операции, похожие на указатели указателей, и случайные_access_iterator typedefs, поэтому он может быть использован в алгоритмах STL, требующих случайных итераторов доступа и обнаруженных с помощью признаков. Дополнительные сведения о членах и операциях класса см. в разделе offset_ptr reference
.