3

free() されたときにオブジェクトのメモリを実際に解放しないが、それをキューに保持し、新しいオブジェクトが要求された場合に以前に割り当てられたオブジェクトを返すジェネリック アロケータ クラスを作成しようとしています。さて、私の頭を包み込めないのは、アロケーターを使用するときにオブジェクトのコンストラクターに引数を渡す方法です (少なくとも、可変個引数テンプレートに頼ることなく)。私が思いついた alloc() 関数は次のようになります。

template <typename... T>
inline T *alloc(const &T... args) {
    T *p;

    if (_free.empty()) {
        p = new T(args...);
    } else {
        p = _free.front();
        _free.pop();

        // to call the ctor of T, we need to first call its DTor
        p->~T();
        p = new( p ) T(args...);
    }
    return p;
}

それでも、今日の C++ (および可変個引数テンプレートをサポートしない古いバージョンの GCC) と互換性のあるコードが必要です。オブジェクトコンストラクターに任意の量の引数を渡す方法は他にありますか?

4

2 に答える 2

3

C++0x より前のコンパイラをターゲットにする必要がある場合は、擬似可変個引数テンプレートを提供する必要があります。つまり、必要なアリティごとにテンプレート関数を提供する必要があります。

template<class T> 
T* alloc() { 
    /* ... */ 
}

template<class T, class A0> 
T* alloc(const A0& a0) { 
    /* ... */ 
}

/* ... */

たとえば、Boost.Preprocessor を使用するか、単純なスクリプトを使用して関数を生成するだけで、プリプロセッサのメタプログラミングを使用して繰り返しを処理できます。

以下は、Boost.PP を使用した簡単な例です。

#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>

template<class T>
T* alloc() {
    return new T;
}

#define FUNCTION_ALLOC(z, N, _) \
  template<class T, BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(N), class T)> \
  T* alloc(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, BOOST_PP_INC(N), const T, &p)) { \
     return new T( \
       BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(N), p) \
     ); \
  }

BOOST_PP_REPEAT(10, FUNCTION_ALLOC, ~)

#undef FUNCTION_ALLOC

これによりalloc()、最大 10 個の引数のテンプレート関数が生成されます。

于 2010-04-08T14:06:15.720 に答える
1

この問題に対する C++11 以前の解決策allocは、引数のコピーを作成する単純な関数を 1 つだけ提供することです。これは、C++03 アロケーターとすべてのコンテナーが 20 年以上にわたって機能する方法です。コードに適用すると、次のようになります。

template <typename T>
inline T *alloc(const &T arg) {
    T *p;

    if (_free.empty()) {
        p = new T(arg);
    } else {
        p = _free.front();
        _free.pop();

        // to call the ctor of T, we need to first call its DTor
        p->~T();
        p = new( p ) T(arg);
    }
    return p;
}

そして、次のように呼び出します。

// copy construct T into the allocator's memory:
instance_of_your_allocator.alloc(T(1, 2, 3));

このアプローチの欠点は、コピー コンストラクターを使用できるようにする必要があり、コストがかかる操作になる可能性があることです。

もう 1 つの例:

vector<T> vec;
vec.push_back(T(1, 2, 3)); // C++03 way, uses move cons-tor in C++11 if possible.
vec.emplace_back(1, 2, 3); // C++11 way, constructs in-place
于 2012-03-10T13:08:06.197 に答える