8

ドキュメントでは、boost::interprocessコンテナを共有メモリに格納するための要件として次のように述べられています。

  1. STL コンテナーは、アロケーターで割り当てられたメモリが同じ型の他のアロケーターで割り当て解除できると想定しない場合があります。すべての allocators オブジェクトは、1 つのオブジェクトで割り当てられたメモリを他のオブジェクトで割り当て解除できる場合にのみ等しい必要があり、これはoperator==()実行時にのみテストできます。
  2. コンテナーの内部ポインターは型である必要があり、コンテナーは生のポインターであるallocator::pointerと想定しない場合があります。allocator::pointer
  3. allocator::constructすべてのオブジェクトは、関数と関数を介して構築/破棄する必要がありallocator::destroyます。

-std=c++11 (およびブースト 1.53) で gcc 4.7.1 を使用しています。以下に定義された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;

    }
}
4

3 に答える 3

0

C++ 11 では、アロケーターの規則が少し変更されていますが、質問には影響しないと思います。

おそらく最初に、標準がそれについて何を述べているかを知りたいと思うでしょう。ただし、実際には、特定の STL 実装が標準に準拠しており、バグが含まれていないかどうかを確認する必要があります。

2番目の部分については、ソースにアクセスして確認することを強くお勧めしますが、実際にはそれほど難しくありません.

また、テストを記述して、実際に正しく機能しているかどうかを確認することもできます。

  • カスタム アロケータを作成します。
    • カスタム型をポインター、const ポインターとして使用します。
    • では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 (適切に実装された) vector がどこからともなくアロケータを取得する方法はありません。提供されたアロケーターを使用し、すべてに使用します。operator== に関しては、boost のアロケータに実装されているため、operator== を必要に応じて機能させるのは boost の問題です。標準で確認できませんでしたが。

2バグがstd::vector<T, YourAllocator>::pointerなければ、アロケータのポインタであるべきです。cppreference.comはそれを言い、標準はそれを言います(「テンプレートクラスベクトル」を探してください):

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

同じ標準ではアロケーターについて次のように述べられていますが、この国際標準で説明されているコンテナーの実装では、アロケーター テンプレートのパラメーターが、表 6 の要件に加えて、次の 2 つの追加要件を満たしていると想定することが許可されています。

-- 特定のアロケータ型のすべてのインスタンスは交換可能である必要があり、常に互いに同等である必要があります。

-- typedef メンバーの pointer、const_pointer、size_type、および difference_type は、それぞれ T*、T const*、size_t、および ptrdiff_t である必要があります。

したがって、実際には標準ではポインター型を使用できませんが、実際の STL 実装は機能すると思います。

3メソッドの実装をチェックしてstd::vector<T>::clear()、allocator::destroy が呼び出されているかどうかを確認します。メソッドの実装をチェックstd::vector<T>::resize()して、allocator::construct が使用されているかどうかを確認してください。標準で destroy および construct を呼び出す要件を見つけることができませんでした。

于 2013-03-14T18:52:05.760 に答える