3

我正在尝试编写一个通用分配器类,它在空闲()时不会真正释放对象的内存,而是将其保存在队列中,如果请求新的对象,则返回先前分配的对象。现在,我无法理解的是如何在使用我的分配器时将参数传递给对象的构造函数(至少不诉诸可变参数模板)。我想出的 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

当您需要针对 pre-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的函数来构造其参数的副本。20 多年来,这就是 C++03 分配器和所有容器的工作方式。将它应用到您的代码中,它变成:

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));

这种方法的缺点是它需要一个可用的复制构造函数,并且它可能是一个昂贵的操作。

再举一个例子:

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 回答