V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kerrspace
V2EX  ›  程序员

C++一个指针,我怎么知道传进来的地址是在堆上还是在栈上?

  •  
  •   kerrspace · 2022-10-06 22:44:12 +08:00 · 2820 次点击
    这是一个创建于 539 天前的主题,其中的信息可能已经有所发展或是发生改变。

    假设我这个指针在 class 里面,从外面传进来的数据它既有可能是一个定义在栈区的 object ,又有可能是 new 在堆区上的

    譬如我有一个 computer class ,然后 computer::computer(cpu*, gpu*, memory*) 在 int main 里面,我既可以 cpu c; gpu g; meory m; 然后 computer(&c, &g, &m)

    也可以 computer(new cpu, new gpu, new memory)

    那我在 class 里面怎么优雅地判断是哪一种情况?(要不要析构的时候销毁这三个 new ?)

    BTW 。。我知道最简单的方法肯定是你就不要这么写

    22 条回复    2022-10-08 09:42:55 +08:00
    lmshl
        1
    lmshl  
       2022-10-06 22:48:27 +08:00 via iPhone
    按 c++ move 写不就行了?
    lmshl
        2
    lmshl  
       2022-10-06 22:49:34 +08:00 via iPhone
    不使用 move 的话,比较简单的原则是谁创建谁销毁
    yanqiyu
        3
    yanqiyu  
       2022-10-06 22:55:49 +08:00
    真的写出这种代码的话给调用者带来的迷惑不是一点半点...
    堆栈生长方向不一样,你随便把这个指针和局部变量比大小就行,毕竟是 caller 传给你的
    但是不要这么做,最好要么始终不转移所有权,要么始终转移所有权,要么用智能指针
    gulu
        4
    gulu  
       2022-10-06 22:57:09 +08:00 via iPhone
    gulu
        5
    gulu  
       2022-10-06 23:01:31 +08:00 via iPhone   ❤️ 1
    判断一个内存段是否属于 heap ,需要借用 mm_struct 里面的 start_brk(heap 内存段的开始位置) 和 brk(heap 内存段的结束位置)。vma 的开始和结束地址在 mm_struct 的 start_brk 和 brk 之间,则说明地址在 heap 内存中。
    leimao
        6
    leimao  
       2022-10-06 23:09:08 +08:00
    > 那我在 class 里面怎么优雅地判断是哪一种情况?(要不要析构的时候销毁这三个 new ?)
    最好不要这么干,object 不 own 那些 memory ,就别去干 delete 的事。
    heiher
        7
    heiher  
       2022-10-06 23:15:20 +08:00 via Android
    c++不用自动内存管理,就要显式约定 ownership ,不需要判断
    BrettD
        8
    BrettD  
       2022-10-06 23:16:27 +08:00 via iPhone
    你这样写还这样问就说明没有把所有权归属问题想清楚
    leonshaw
        9
    leonshaw  
       2022-10-06 23:16:40 +08:00
    你也知道不要这么写,所有权也是函数 contract 的一部分。并且完全可以分配一块堆内存作为线程的栈(默认情况也是和堆类似分配方式)。
    shawnsh
        10
    shawnsh  
       2022-10-06 23:19:46 +08:00 via Android
    谁创建的指针,谁知道是用的哪个区,让他管回收,你只是使用,你不要管回收。如果要回收,那么就需要知道该指针的类型,是哪个区的。所以你要封装个对象,里面要有一个指针,还要有指针所在的区域,还要有是否调用者可以释放的标记,是不是超级麻烦
    Nitroethane
        11
    Nitroethane  
       2022-10-06 23:21:50 +08:00   ❤️ 1
    @gulu #5 写内核模块才能这样搞,用户态进程肯定不行。

    解析 /proc/[pid]/maps 文件,从这个文件中可以知道进程的虚拟地址空间布局,包括 stack 和 heap 的地址范围。
    ColorfulBoar
        12
    ColorfulBoar  
       2022-10-07 02:11:53 +08:00
    正常人的裸指针不带 ownership (当然喜欢指针的没一个正常人就是了)
    另外在内存哪个区域和 storage duration 是两码事,比如如果外面是个 coroutine 那即使已经知道是 automatic storage duration+没有重载 operator new ,也可能被分配在堆上(同时编译器也可能优化成在栈上)
    mingl0280
        13
    mingl0280  
       2022-10-07 09:20:44 +08:00 via Android
    不要删就完了。
    谁分配的谁清理。
    dearmymy
        14
    dearmymy  
       2022-10-07 09:39:40 +08:00
    开始想判断堆跟栈 地址,但想想如果这个整个都 new 在堆里。
    感觉靠谱的,得栈帧一步步回溯?然后判断堆地址区间?
    iceheart
        15
    iceheart  
       2022-10-07 09:52:39 +08:00 via Android
    通过调用栈取到最接近栈顶的地址,定义一个栈上的变量,取到这个变量的地址。在此区间的指针就是栈上的
    littlewing
        16
    littlewing  
       2022-10-07 10:51:55 +08:00
    在堆上也不一定要 delete 啊,说不定创建者自己要 delete 呢,说白了还是 ownership 的问题,建议你用 unique_ptr 或 shared_ptr 。一定要用裸指针的话,遵循谁 new 谁 delete 的原则,除非是在异步回调里
    wtsamuel
        17
    wtsamuel  
       2022-10-07 11:32:02 +08:00
    那应该去问创建这个指针的人
    还得讨论下应不应该修改, 删除这个指针的值
    whi147
        18
    whi147  
       2022-10-07 11:39:36 +08:00 via iPhone
    谁创建谁清理,全部更换智能指针,少用共享智能指针
    calloc
        19
    calloc  
       2022-10-07 11:39:51 +08:00 via iPhone
    去 /proc/self/maps 比对一下
    yolee599
        20
    yolee599  
       2022-10-07 12:57:36 +08:00 via Android   ❤️ 1
    谁创建谁清理原则,不要随便 delete 别人传进来的指针
    FrankHB
        21
    FrankHB  
       2022-10-07 16:35:01 +08:00
    你要优雅,就先干掉 computer::computer(cpu*, gpu*, memory*)这种看不出让你怎么干的废物签名。
    基本上除非在写分配器的实现,你一个一般应用的作者,没什么理(资)由(格)在 API 中用指针。
    (写内核之类的东西原则上几乎都得依赖 ABI ,使用的假设比 C++的指针多得多。)
    hu8245
        22
    hu8245  
       2022-10-08 09:42:55 +08:00 via Android
    我实在想不出什么普通场景需要这种骚操作,你操作了,人家释放的时候出问题了,算函数内的操作还是 caller ?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2769 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 12:13 · PVG 20:13 · LAX 05:13 · JFK 08:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.