placement new

C++11 中,形如 new(buffer)T; 的语句即为 placement new 语法

如何让一个已经 contructed 的 object 重新调用其 constructor?placement new 就是答案。

placement new 可以指定 "new/新建" 的内存的具体位置。

  • there's no "placement delete". with placement new, you could "new" memory in stack/heap/static/thread_local storage area.
  • there's no book keeping area for placement new. The "allocated" size is exactly the same with the size of the object which was newed.
    • (注意"new/新建/allocated"是引号,因为实际上并没有新的内存被 alloc)
  • placement new 出来的 object,"销毁"时不会自动调用其 destructor,如果需要的话,可以手动调用它
    • (为什么"销毁"是引号?难以言喻,读完本篇应该可以意会)

首先补充一点:一般来说,C++ 有四种 storage categories

  • static storage duration: 即 global 和 staic local
  • thread_local storage duration: C++11 new keyword. 与线程同生同死
  • dynamic storage duration: 即存在于 Heap,例如在 Linux x64 中地址从小到大增长
  • automatic storage duration: 即存在于 Stack,例如 function frame
  • 第五种 register 在 C++ 中俨然已如空气,一般编译器都会直接忽略它。

举一个 auto/thread_local/static 的例子:

struct T {
    int val;
    T(int v) : val(v) {}
    T(int a, int b) : val(a + b) {}
    ~T() {
        cout << "val: " << val << endl;
    }
};
{
    // static char .. | thread_local char ..
    char buffer[16];
    T* ptr = new (buffer) T(10);

    // 此时 ptr->val == 10, ptr的值 == buffer的首地址
    cout << ptr->val;
}
// 离开 scope,对于 auto 类型的 char buffer[10],其内存被回收。
// ptr->~T() 不会被调用。注意是 stack 中的 buffer 数组的析构函数被调用。
// 当然对于 buffer 这样的 POD 并没有析构函数
//
// 如果 buffer 是 thread_local,则当 thread 结束并被join 或者 detach 后,
// buffer 的内存被回收。
//
// 如果 buffer 是 static,则当 process exit 时,process 所有的内存被操作系统回收,
// 当然也包括 buffer。

再举一个例子:

{
    // class T constructor T(int);
    T t(1);
    T* ptr = &t;

    // 这里调用它只是为了打印。实际使用中析构函数会释放一些资源,
    // 对应构造函数会创建一些资源。
    ptr->~T();

    // class T constructor T(int, int);
    new (ptr) T(2, 3);
}
// t 的生命结束时,t.~T() 再次被调用

再举一个 heap 的例子:

{
    // 申请 sizeof(T) 的内存 + 一定数量的 book keeping 内存
    T* ptr = new T(1);

    // T(1)的内存被直接覆盖了,注意其 destructor 没有被调用
    T* ptr2 = new (ptr) T(2, 3);

    // ptr->~T() 被调用。一共有:一次底层 malloc,两次 ctor,
    // 一次 dtor,一次底层 free 被调用。
    // 同时 delete()库函数 会 free book keeping area
    delete ptr;
}

本文分享自微信公众号 - Toddler的笔记(gh_5708a01db935),作者:李国诚

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-06-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 智能指针

    刚学编程时,最常听到的一句话是不是“new 的内存用完要记得 delete,不然会造成内存泄漏”?然而事实上是:

    JIFF
  • 【介绍一些好用的轮子(1)】类型安全的字符串格式化输出

    学过 C 语言的同学可能对 printf 都不陌生,也对用 "%d" 这种格式控制符对应于打印一个 int 也不陌生。然而这种打印方式是被 C++ 唾弃的,于是...

    JIFF
  • CTP 看穿式监管版本,收集信息为什么会失败?

    就此我先询问了 CTP 官方交流群,官方给出的解答是,需要链接新的信息采集的库 WinDataCollect。

    JIFF
  • 设计模式(一) | 啥是工厂模式和策略模式?

    谭庆波
  • 设计模式(一) | 啥是工厂模式和策略模式?

    谭庆波
  • Flask 扫盲系列-Flask 上下文

    上一次我们做了一个简单的在线股票走势网站,今天我们来继续完善下网站功能,并学习些新的 Flask 知识点。

    周萝卜
  • 大数据时代下数据挖掘技术的应用

    原文链接:https://mp.weixin.qq.com/s/bxSEO4gKQ-BbDWT1BNnwyw

    月牙寂道长
  • Java集合详解3:一文读懂Iterator,fail-fast机制与比较器

    《Java集合详解系列》是我在完成夯实Java基础篇的系列博客后准备开始写的新系列。

    Java技术江湖
  • Java集合详解3:一文读懂Iterator,fail-fast机制与比较器

    本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看

    Java技术江湖
  • 罗马数字背后的秘密——LeetCode XII XIII 题记

    印象中的罗马数字,多出现在文档标题或序号中:I、II、III、IV、V、VI 等。它是阿拉伯数字传入之前使用的一种数码。其采用七个罗马字母作数字:Ⅰ(1)、X(...

    TTTEED

扫码关注云+社区

领取腾讯云代金券