如何实现一个具有placement new和emplace功能的简单容器?

2023-11-26

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

为此,我决定使用placement new并将内存管理完全委托给容器实现(在以下位置找到了一些有关placement new的有用信息)drdobbs).

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

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

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

现在我想要删除重复写入的需要executer在这份声明中。我宁愿写一些类似的东西:

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

or

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

也许可以通过提供适当的模板,但我未能编写模板(请不要使用预处理器宏)。

我发现了一些有用的信息std::allocator这里在drdobbs但不知道如何将其应用于我的问题(此外,该文章是 2000 年的文章,因此不要利用可能的 C++11 优势)。

有人可以帮助我找到一种方法,不再需要给予executer twice?

Edit:审核成功后Jarod42的答案,我更新了我的运行示例代码here.

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

#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> // this don't works
void pushNew(R) {
    push(new (*this) R);
}

第一个答案是Jarod42你想做的:

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

但更重要的是...new (*this) R is 真的很奇怪。看起来你正在构建一个R超越你自己!但你不是,你只是使用该语法来调用你的分配器。这严重违反了最小意外原则。我花了很长时间才明白发生了什么事。

你应该做的是直接使用你的分配器:

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

这更容易理解。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何实现一个具有placement new和emplace功能的简单容器? 的相关文章

随机推荐

  • Subversion - 始终使用我的解决一组文件的冲突

    我们在 subversion 中保留了大量自动生成的代码 有时我正在处理发电机的一个部件 而另一个同事正在处理发电机的另一个部件 我们中的一个人签到 另一个人得到最新的信息 现在我们生成的代码存在冲突 因为它是生成的 所以下次生成器运行时它
  • 获取总和最大的子矩阵?

    Input 二维数组 NxN 矩阵 具有正数和负数元素 Output 任意大小的子矩阵 其总和是所有可能的子矩阵中的最大值 要求 算法复杂度为O N 3 History 在算法师 Larry 的帮助下以及对 Kadane 算法的修改 我成功
  • java中查找字符串的所有大写字母

    所以我试图找到用户输入的字符串中的所有大写字母 但我不断收到此运行时错误 Exception in thread main java lang StringIndexOutOfBoundsException String index out
  • 删除特定匹配后的所有字符

    我正在使用 Notepad 从模式末尾删除一些不需要的字符串 这对我来说已经是我的生活了 我有以下几组字符串 myApp ComboPlaceHolderLabel myApp GridTitleLabel myApp SummaryLab
  • 使用 importlib 动态导入包含相对导入的模块

    我试图弄清楚如何以编程方式执行包含相对导入的模块 伪代码 spec importlib util spec from file location name path mod importlib util module from spec s
  • Xcode 和 XIB 自我文档 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 有没有一个工具可以记录许多 Xcode 绑定 插座和IBAction绑定 键值绑定等 我看过以下主题Doxygen and 标题文档 但是这些文档程
  • 如何使用FirefoxProfile通过Firefox浏览器自动下载?

    我正在使用 selenium java 我需要下载 pdf 文件 我提到this this并且this答案在这里 但似乎在我的情况下没有任何效果 是否是由于设置了新的 Firefox 驱动程序实例 即System setProperty w
  • 有没有办法在 Visual Studio 中的 F# 中发出阴影值警告?

    对我来说 现有价值观的阴影如下所述 阴影和嵌套函数 F 中不可变 f 重复定义 FSharp 好玩又赚钱的评论 似乎违背了使 F 如此强大的不变性和类型安全的概念 F 中的阴影工作不同的比在 C 中 我花了相当长的时间才发现我的代码中的错误
  • 在 Haskell 中检索文件大小的 hFileSize 更快替代方案?

    我想知道如何以最少的开销获取 haskell 中文件的大小 现在我有以下代码 getFileSize FilePath gt IO Integer getFileSize x do handle lt openFile x ReadMode
  • PHP 数组的平均时间

    如何从一组时间中计算出平均时间 我有一个看起来像这样的数组 17 29 53 16 00 32 我希望达到这个结果16 45 12使用 PHP date H i s array sum array map strtotime array c
  • 如何在 Google Chrome 中查看 HTTP 标头?

    在 9 x 之前 标题位于开发人员工具中的资源下 但现在我在任何地方都找不到它 我不确定您的确切版本 但 Chrome 有一个 网络 选项卡 其中包含多个项目 当我单击它们时 我可以在选项卡右侧看到标题 Press F12 on windo
  • 我成功地从 C# 调用了 advapi32 的 LsaEnumerateAccountRights()。现在如何解组它返回的 LSA_UNICODE_STRING 数组?

    它是一个指向数组的指针LSA UNICODE STRING结构 我发现一些代码可以做相反的事情 即创建一个LSA UNICODE STRING来自 C 字符串 您可以在下面的帮助程序代码部分中看到这一点 我正在做什么 包括打电话给LsaEn
  • 入口 nginx 缓存

    我试图弄清楚如何使用 nginx 代理缓存和一些特定的规则 例如 当我托管 Ghost 或 Wordpress 时 我不想缓存管理部分 使用服务器片段 我尝试了很多不同的组合 但管理部分的缓存仍然存在问题 nginx ingress kub
  • 如何在 Grails 中创建包含所有 i18n 消息的映射

    我需要它在控制器中渲染它的一部分 例如 class MessageController def index def messageMap listAlli18nMessages the question render contentType
  • Python 3.5 与 Python 2.7:模块导入子模块

    过去几个小时我一直在谷歌上搜索这个问题 但在任何地方都找不到类似的问题 此外 2 7 和 3 5 的文档似乎相同 因此我认为这种行为没有记录 这是我的目录结构 project project py api init py subapi in
  • maven-jaxb2-plugin VS jaxb2-maven-plugin 用于多个模式

    我有多个 xsd 模式 我想将它们解组到不同的包中same folder target generated sources xjc 我尝试了这两个插件 似乎都可以很好地使用这两种配置 但在 maven jaxb2 plugin 的情况下 e
  • MYSQL左连接结果的最后一行

    我需要一些 MYSQL 帮助 我有一个名为 Tickets 的表和一个名为 statusLogs 的表 我该如何 select t sl statusId from ticket LEFT JOIN select from statusLo
  • 使用扩展方法的实体框架分页很慢?

    我在 C 的实体框架中遇到查询缓慢的问题 我创建了一个名为 Page 的扩展方法来处理分页 但是当我使用它时 查询变得非常慢 如果我只是执行 Skip page Value pageSize Value Take pageSize Valu
  • 当目标是类型时,为什么 Coq 不允许反转、析构等?

    When refine正在运行一个程序 我试图通过以下方式结束证明inversion on a False假设当目标是Type 这是我尝试做的证明的简化版本 Lemma strange1 forall T Type 0 gt 0 gt T
  • 如何实现一个具有placement new和emplace功能的简单容器?

    我需要实现一个容器来容纳一定数量的元素 并且出于某种原因 它必须在没有任何堆分配的情况下工作 另一个要求是 容器元素不应以任何方式复制或移动 它们必须直接构建到容器分配的内存中 为此 我决定使用placement new并将内存管理完全委托