C ++类包装器和放置新的

时间:2015-09-25 14:11:25

标签: c++ wrapper placement-new

我有一个模板容器类,需要将附加信息与用户指定类型的每个实例相关联。

容器指定包含指定类型和附加信息的包装器结构......

template<typename T> class Container
{
    ...

    struct Wrapper
    {
        T   mType;
        int mInfo;
    };
}

在初始化时,使用动态分配的Wrapper实例(即Wrapper *)填充容器。用户可以pop()一个实例,容器将返回一个转换为T *。用户可以push()一个实例,容器将转换回Wrapper *。

如果数据类型可以默认构造,这可以正常工作。但是,情况并非总是这样,我想让用户提供一个在初始化期间调用的分配函数,它构造了它喜欢的数据类型。容器可以要求该功能的特定签名。

template<typename T> template<typename F> void Container<T>::init(F allocator);

我正在努力解决的是在函数分配数据类型时如何分配包装器。我已经考虑过使用placement new,其中容器为Wrapper分配了足够的空间,并将地址传递给函数以进行数据类型的新放置。

有更简洁的方法吗?

2 个答案:

答案 0 :(得分:0)

您不需要为此分配功能。相反,你需要像标准容器中的emplace_push。

答案 1 :(得分:0)

我只是将用于构造T的参数添加为Container的模板参数,并使用它们来构造T.为了允许动态构造T对象,容器构造函数接受一个指向函数的指针作为参数。参数是创建等级的整数,T构造函数的默认参数,并返回T构造函数的参数元组(std::tuple<U...> (*getInitParam)(int rank, U... params)):

template<typename T, typename ...U>
class Container {
    struct Wrapper {
        T mType;
        int mInfo;

        Wrapper(int mInfo, U... params): mType(params...), mInfo(mInfo) {}
    };

    std::stack<Wrapper *> stack;

    int get_mInfo() {
        static int info = 0;

        return info++;
    }
    std::tuple<U...> (*getInitParam)(int rank, U... params);

public:
    T* pop() {
        // should control stack is not empty
        Wrapper *w = stack.top();
        stack.pop();
        return &w->mType;
    }
    void push(T* type) {
        char *p = reinterpret_cast<char *>(type);
        p -= offsetof(Wrapper, mType);
        Wrapper *w = reinterpret_cast<Wrapper *>(p);
        // would need to control that *w is a valid Wrapper
        stack.push(w);
    }
    void init(int n, U... params) {
        std::tuple<U...> orig = std::make_tuple(params...);
        for (int i=0; i<n; i++) {
            if (getInitParam != nullptr) {
                std::tie(params...) = orig;
                std::tuple<U...> tparams = (*getInitParam)(i, params...);
                std::tie(params...) = tparams;
            }
            Wrapper *w = new Wrapper(get_mInfo(), params...);
            stack.push(w);
        }
    }
    Container(std::tuple<U...> (*getInitParam)(int rank, U... params) = nullptr)
        : getInitParam(getInitParam) {}
    ~Container() {
        while(! stack.empty()) {
            Wrapper *w = stack.top();
            delete w;
            stack.pop();
        }
    }
};

用法示例:

std::tuple<size_t, char> doInit(int i, size_t szmin, char c) {
    return std::make_tuple(szmin + i, c);
}

int main() {
    Container<std::string, size_t, char> cont(&doInit);
    cont.init(10, 5, 'x');

    std::string* str0 = cont.pop();
    std::string* str = cont.pop();
    std::cout << *str0 << std::endl;
    std::cout << *str << std::endl;

    *str0 = "bar";

    cont.push(str0);
    cont.push(str);

    str0 = cont.pop();
    str = cont.pop();

    std::cout << *str << std::endl;
    cont.push(str);
    cont.push(str0);
    return 0;
}

这正确输出:

xxxxxxxxxxxxxx
xxxxxxxxxxxxx
bar

仍然需要实现mInfo用法,但它应该是一个起点......

相关问题