如何实现具有放置新功能和放置功能的简单容器? [英] How to implement a simple container with placement new and emplace functionality?

查看:112
本文介绍了如何实现具有放置新功能和放置功能的简单容器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要实现一个容器来容纳一定数量的元素,并且由于某种原因,它必须在没有任何堆分配的情况下工作.另一个要求是,不得以任何方式复制或移动容器元素.它们必须直接构造到容器分配的内存中.

I need to implement a container to hold an amount of elements and for some reason, it has to work without any heap allocation. Another requirement is, that the container elements should not be copied or moved in any way. They have to constructed directly into the memory allocated by the container.

为此,我决定使用newplacement并将内存管理完全委派给容器实现(在

For that, I decided to use placement new and delegate the memory management completely to the container implementation (found some useful information about placement new at drdobbs).

此处找到了一个运行示例. (请注意,使用new uint8_t[size]std::queue只是为了使示例保持简单.我的实际代码具有更复杂的,无堆的实现.)

A running example is found here. (Please note, that the use of new uint8_t[size] and std::queue is just to keep the example simple. My real code has more complex, heap-less implementation instead.)

到目前为止,这非常有效,因为客户端代码必须通过如下调用将元素放入容器中:

This perfectly works so far, as the client code has to put elements into the container with calls like:

executer.push(new (executer) MyRunnable("Hello", 123));

现在,我想删除此语句中重复写入executer的需要.我想写例如:

Now I want do remove the need of the repeated write executer in this statement. I would rather like to write something like e.g.:

executer.pushNew(MyRunnable("Hello", 123));

executer.pushNew(MyRunnable, "Hello", 123);

也许可以通过提供适当的模板来实现,但是我未能编写出一个模板(请没有预处理器宏).

maybe by providing an appropriate template but I failed to write one (no preprocessor macros, please).

我在std::allocator的一些有用信息> drdobbs ,但不知道如何将其应用于我的问题(此外,该文章的版本为2000年11月,因此不要利用C ++ 11的可能优势).

I'd found some useful information about std::allocator here at drdobbs but don't know how to apply it to my problem (further, the article is of anno 2000 and so don't take use of possible C++11 advantages).

有人可以帮我找到不再需要两次给executer的方法吗?

Could one help me to find a way to not longer need to give the executer twice?

编辑:成功批准 Jarod42 的答案后,我已经更新了跑步机示例代码此处.

After successful approving Jarod42's answer, I'd updated my running example code here.

关于历史,这里是我最初提出的问题的原始示例代码:

And for the history, here the original example code of my initial question:

#include <iostream>
#include <queue>


class Runnable {
    // Runnable should be uncopyable and also unmovable
    Runnable(const Runnable&) = delete;
    Runnable& operator = (const Runnable&) = delete;    
    Runnable(const Runnable&&) = delete;
    Runnable& operator = (const Runnable&&) = delete;    
public:
    explicit Runnable() {}
    virtual ~Runnable() {}
    virtual void run() = 0;
};


class MyRunnable: public Runnable {
public:
    explicit MyRunnable(const char* name, int num): name(name), num(num) {}
    virtual void run() override {
        std::cout << name << " " << num << std::endl;
    }
private:
    const char* name;
    int num;
};


class Executer {
    // Executer should be uncopyable and also unmovable
    Executer(const Executer&) = delete;
    Executer& operator = (const Executer&) = delete;    
    Executer(const Executer&&) = delete;
    Executer& operator = (const Executer&&) = delete;    
public:
    explicit Executer() {    
    }

    void* allocateEntry(size_t size) {
        // this heap allocation is just to keep this example simple
        // my real implementation uses it's own memory management instead (blockpool)
        return new uint8_t[size];
    }

    void push(Runnable* entry) {
        queue.push(entry);
    }

    template <typename R> // this don't works
    void pushNew(R) {
        push(new (*this) R);
    }

    inline friend void* operator new(size_t n, Executer& executer) {
        return executer.allocateEntry(n);
    }

    void execute() {
        while (queue.size() > 0) {
            Runnable* entry = queue.front();
            queue.pop();
            entry->run();
            // Now doing "placement delete"
            entry->~Runnable();
            uint8_t* p = reinterpret_cast<uint8_t*>(entry);
            delete[] p;
        }

    }

private:
    // this use of std::queue is just to keep this example simple
    // my real implementation uses it's own heap-less queue instead
    std::queue<Runnable*> queue {};
};


int main() {
    Executer executer;
    executer.push(new (executer) MyRunnable("First", 1));
    executer.push(new (executer) MyRunnable("Second", 2));
    executer.push(new (executer) MyRunnable("Third", 3));

    // but want to use it more like one this 
    //executer.pushNew(MyRunnable("Fifth", 5));  // how to implement it?
    //executer.pushNew(MyRunnable, "Sixth", 6);  // or maybe for this usage?

    executer.execute();
}

推荐答案

使用:

template <typename R, typename... Ts>
void pushNew(Ts&&... args) {
    push(new (*this) R(std::forward<Ts>(args)...));
}

您可以写:

executor.PushNew<MyRunnable>("Hello", 123);

代替

executer.push(new (executer) MyRunnable("Hello", 123));

这篇关于如何实现具有放置新功能和放置功能的简单容器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆