Удовлетворяет ли std :: vector требованиям контейнера для распределителей Boost.Interprocess?

В boost::interprocess Документация называется требованием хранения контейнеров в общей памяти:

  1. Контейнеры STL могут не предполагать, что память, выделенная с помощью распределителя, может быть освобождена с другими распределителями того же типа. Все объекты распределителей должны сравниваться равными только в том случае, если память, выделенная одному объекту, может быть освобождена с другим, и это можно проверить только с operator==() во время выполнения.
  2. Внутренние указатели контейнеров должны быть типа allocator::pointer и контейнеры могут не принять allocator::pointer это необработанный указатель
  3. Все объекты должны быть построены-уничтожены через allocator::construct а также allocator::destroy функции.

Я использую GCC 4.7.1 с -std = c ++ 11 (и повысить 1,53). Безопасно ли использовать нижеуказанные ShmVector тип?

typedef boost::interprocess::allocator<int,
boost::interprocess::managed_shared_memory::segment_manager>  ShmemAllocator;
typedef std::vector<int, ShmemAllocator> ShmVector;

Я попробовал фиктивный процесс, который использует этот тип, и похоже, что он работает, но я все еще не уверен, что вектор в gcc4.7.1 действительно удовлетворяет всем требованиям. Я особенно не уверен насчет первого требования.

#include <iostream>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <vector>
#include <cstdlib> //std::system

typedef boost::interprocess::allocator<int,
boost::interprocess::managed_shared_memory::segment_manager>  ShmemAllocator;
typedef std::vector<int, ShmemAllocator> ShmVector;

int main(int argc, char *argv[])
{
if(argc == 1){ //Parent process

struct shm_remove
{
shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
~shm_remove(){ boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
} remover;

//Create a new segment with given name and size
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only,
"MySharedMemory", 65536);

//Initialize shared memory STL-compatible allocator
const ShmemAllocator allocator(segment.get_segment_manager());

ShmVector* v = segment.construct<ShmVector>("ShmVector")(allocator);
v->push_back(1); v->push_back(2); v->push_back(3);

//Launch child process
std::string s(argv[0]); s += " child ";
if(0 != std::system(s.c_str()))
return 1;

} else { // Child process

//Open the managed segment
boost::interprocess::managed_shared_memory segment(
boost::interprocess::open_only, "MySharedMemory");

//Find the vector using the c-string name
ShmVector *v = segment.find<ShmVector>("ShmVector").first;

for (const auto& i : *v) {
std::cout << i << " ";
}
std::cout << std::endl;

}
}

8

Решение

В C ++ 11 правила выделения немного изменились, но я не думаю, что это влияет на ваш вопрос.

Вы, вероятно, хотите сначала узнать, что говорит об этом стандарт. Но на самом деле вы хотите проверить, соответствует ли ваша конкретная реализация STL стандарту и не содержит ли ошибок.

Во второй части я настоятельно рекомендую обратиться к источникам и просто проверить это, на самом деле это не так сложно.

Кроме того, вы можете написать свои тесты, чтобы увидеть, действительно ли они работают правильно:

  • Создать собственный распределитель:
    • использовать некоторый пользовательский тип как указатель, указатель констант;
    • В construct(), destruct() посчитать количество звонков;
  • Создайте YourCustomType для использования с распределителем, который также считает количество конструкций / разрушений.
  • Теперь создайте std::vetor<YourCustomType, YourCustomAllocator<YourCustomType>> Например, вставить некоторые элементы, очистить вектор, уничтожить его и посмотреть, если:
    • количество construct() destruct() количество вызовов равно числу разрушений конструкций YourCustomType,
    • typeid(YourCustomAllocator::pointer) == typeid(std::vetor<YourCustomType, YourCustomAllocator<YourCustomType>>::pointer)

Таким образом, вы можете быть уверены, что все ограничения применяются.

Что касается первой части вопроса, вот старый стандарт C ++ (не C ++ 11).

1 Нет никакого способа (правильно реализованного) вектора, который вывезет распределитель из ниоткуда. Он будет использовать любой предоставленный вами распределитель и будет использовать его для всего. Что касается оператора ==, он реализован в распределителе boost и, таким образом, проблема boost заключается в том, чтобы оператор == работал так, как им требуется. Хотя я не смог найти подтверждение в стандарт.

2 Если нет ошибки, std::vector<T, YourAllocator>::pointer должен быть указателем распределителя. cppreference.com говорит, что, и стандарт Говорит, что, (ищите «Вектор класса шаблона»):

    typedef typename Allocator::pointer               pointer;
typedef typename Allocator::const_pointer         const_pointer;

Хотя тот же стандарт говорит об этом распределители:
Реализация контейнеров, описанных в этом международном стандарте
разрешено предполагать, что их параметр шаблона Allocator соответствует
следующие два дополнительных требования помимо тех, что приведены в таблице 6.

—Все экземпляры данного типа распределителя должны быть
изменчивы и всегда сравнивают друг с другом.

—Указатель членов typedef, const_pointer, size_type и Different-
Тип ence_type должен быть T *, T const *, size_t и ptrdiff_t,
соответственно.

Итак, на самом деле стандарт не позволяет использовать какие-либо типы указателей, но я предполагаю, что фактические реализации STL будут работать.

3 Просто проверьте std::vector<T>::clear() реализация метода, чтобы увидеть, вызывается ли allocator :: destroy. Проверьте std::vector<T>::resize() реализация метода, чтобы увидеть, используется ли allocator :: construct. Я не смог найти требование вызова уничтожить и построить в стандарт.

0

Другие решения

Я думаю, что ответ — нет. Потому что на практике (в C ++ 98) и в теории (стандарт C ++ 11), std::vector указатель не может быть чем-то другим, чем T*,

Поэтому boost::interprocess::vector<T> использования boost::container::vector<T, boost::interprocess::allocator<T>> (вместо std::vector<T, boost::interprocess::allocator<T>>).

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector