V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
kerrspace
V2EX  ›  程序员

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

  •  
  •   kerrspace · Oct 6, 2022 · 3883 views
    This topic created in 1309 days ago, the information mentioned may be changed or developed.

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

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