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

怎样在 C++里用 C-style 按行读取文件并不分配 heap 内存?

  •  
  •   dangyuluo · 2022-09-14 13:09:01 +08:00 · 2669 次点击
    这是一个创建于 802 天前的主题,其中的信息可能已经有所发展或是发生改变。

    同事的破要求,按行读取一个文件,不让用 ifstream ,仅仅是因为“We don't have a precise understanding of how much memory the program will allocate”。想用getline但是getline也会分配内存。请问有没有什么现成的轮子?谢谢。

    25 条回复    2022-09-16 01:38:29 +08:00
    clrss
        1
    clrss  
       2022-09-14 13:32:22 +08:00
    C++不也能 scanf?
    Jirajine
        2
    Jirajine  
       2022-09-14 14:14:31 +08:00
    那就用 read 手写?自己在栈上静态分配 buf ,读到 buf 里自己按换行符拆分。
    yolee599
        3
    yolee599  
       2022-09-14 14:30:00 +08:00
    fgets 不行吗?
    hankai17
        4
    hankai17  
       2022-09-14 16:07:19 +08:00
    fread ?
    newmlp
        5
    newmlp  
       2022-09-14 16:12:28 +08:00
    mmap
    lakehylia
        6
    lakehylia  
       2022-09-14 16:20:15 +08:00
    按行读取,必然涉及到不定长度的数组啊,你不在 heap 上建数组,难道在栈上?你栈能有多大啊。。。
    ysc3839
        7
    ysc3839  
       2022-09-14 17:53:27 +08:00
    直接 mmap 吧
    nightwitch
        8
    nightwitch  
       2022-09-14 18:18:54 +08:00 via Android
    按行读取
    不用堆
    来个 100M 的单行文件必定栈溢出
    GeruzoniAnsasu
        9
    GeruzoniAnsasu  
       2022-09-14 18:21:43 +08:00
    看描述怎么感觉 ABproblem

    你 precisely alloc 一块 heap 来做 buffer 不行么
    iyeatse
        10
    iyeatse  
       2022-09-14 18:23:11 +08:00 via iPhone
    你可以跑个 benchmark ,给他一个 precise understanding
    haolongsun
        11
    haolongsun  
       2022-09-14 19:18:34 +08:00
    不知道 size 有多大?还敢在栈上存?
    cnbatch
        12
    cnbatch  
       2022-09-14 20:46:35 +08:00
    可以反问你的同事一句:那你能精确知道文件的每一行有多长吗?你能保证文件每一行不会超出预分配的固定大小?
    重点在于“你能保证吗?”
    言外之意就是:“出了事你负责”。
    cnbatch
        13
    cnbatch  
       2022-09-14 20:48:32 +08:00
    如果你的同事被要求“出了事你负责”还不怂的话,那就正好,把相关保证言论保存下来(最好能放到 Git 记录里面),一旦栈溢出就甩锅给他
    chenzhongxiang
        14
    chenzhongxiang  
       2022-09-14 21:03:58 +08:00
    我的实践是可以用 mmap ,逐个字符扫描检查换行,不过不允许分配堆内存你拿到了一段比较长的行(例如 1MB ,这个问题的关键就是你压根就不知道一行会有多长)你后续的使用也会有诸多棘手的地方。
    更好的实践是不用过多纠结分配堆内存,C 程序员通常应该清楚自己在做什么,合理的分配堆没有任何问题。有一段时间我也尽量避免使用堆内存,错误的以为这样可以提升性能。后来逐渐的意识到没啥必要,你看看 glibc 的源码很多你认为很简单的函数都使用堆内存。你们的项目质量要求比 glibc 还高么。
    个人的常规见解。实际项目可能在某个点就是要求苛刻,那就需要妥善的考虑全局。
    sockpuppet9527
        15
    sockpuppet9527  
       2022-09-14 21:19:23 +08:00
    建议离职,能提出这种不合理的需求的公司可太行了,另外即使是 heap 分内存,也通过类似代理的方式统计。
    mingl0280
        16
    mingl0280  
       2022-09-14 21:39:07 +08:00 via Android
    这个需求太傻 x 了,这么搞肯定栈溢出(正常的栈空间才 8M ),太蠢了……
    除非你按定长字节读取(当然这个效率也不行)
    zengmingyang96
        17
    zengmingyang96  
       2022-09-14 21:51:05 +08:00
    @mingl0280 编译器指定的,想多大就多大
    villivateur
        18
    villivateur  
       2022-09-14 21:56:20 +08:00
    不用 heap 的话,要不在 ZI 区域先定义 1 个 G 的全局变量吧(狗头)
    dangyuluo
        19
    dangyuluo  
    OP
       2022-09-15 02:10:13 +08:00
    @sockpuppet9527 我也想走的,但是给的钱太多了。。。
    mingl0280
        20
    mingl0280  
       2022-09-15 04:44:55 +08:00 via Android
    @zengmingyang96 然后你的进程一创建就被系统 ulimit 给嘎了
    saberlong
        21
    saberlong  
       2022-09-15 07:59:19 +08:00 via Android
    你同事的意思是不是读一行处理一行?
    forcecharlie
        22
    forcecharlie  
       2022-09-15 10:03:35 +08:00
    用栈变量就可以按行读取了,如果是 Windows 用 ReadFile 如果是其他系统用 read ,换行的话用 memchr 快速查找 '\n',不用 fstream 就可以实现。当然这里为了支持任意长度的一行,你需要引入状态。
    hu8245
        23
    hu8245  
       2022-09-15 10:53:22 +08:00
    把此需求转给架构师
    FrankHB
        24
    FrankHB  
       2022-09-15 23:17:14 +08:00
    连 ifstream 都写不出来的好意思纠结怎么 allocate memory ? review 直接穿小鞋。
    (就是自己实现,不止是分析;重点是 basic_filebuf ;别说找不到抄哪。)

    清楚栈可能实际会造成问题是入门,但拿对实现细节和运行时假设的依赖当做拒绝的理由说服力是不大够的。

    言简意赅、强而有力:就你也配挑三拣四?
    就是甲方爸爸都特么不大可能配关心这种问题,还特么是这种方法论上就没靠谱结果的问题。
    合格的 C 和 C++用户:知道 ISO C 和 ISO C++都根本就不管什么栈,哪怕拒绝分配栈给你自动对象于是 int main(){volatile char x = 0;}都炸栈 UB 也照样 conforming——原则上,自动对象根本不需要被 allocate 。
    所以谁倒是给我发明个光扯什么 C++和 C style 就能怎么敲捣出 precise understanding 的方案出来?

    会纠结 allocate memory 的,最起码也得了解一种 allocator model 并且会自己正确实现有实用意义的实例,写出用例说明相对默认策略有效改进在哪。
    如果想装自认为有能力指定全局默认策略的专家,我会把门槛设置到用 C++11 正确实现 std::make_obj_using_allocator ,而不只是稀里糊涂分析具体实现。
    分析不清楚 ISO C 和 POSIX 等相关 C API 设计缺陷甚至只会无脑 malloc 连 realloc 哪里弱鸡都没个谱的,禁止覆盖选型决策。
    毕竟,这里有人也提到了,正常人是“通常应该清楚自己在做什么”,而不是“清楚系统和程序在做什么”。事实上,正常语言实现的设计从一开始压根就不会照顾任意允许 yy“清楚”细节的伪需求。

    @Jirajine “栈上”和“静态”,你是想说哪个?(虽然看上去哪个都说得通。)

    @GeruzoniAnsasu 想多了。就这观念,能 precisely alloc heap 就有鬼了,占位的 header 多大怕都搞不清楚。

    @iyeatse 就这症状,想 precise 是不是还要教清楚怎么算 I/O buffer ?
    典型 C 实现中有些 buffer 配置可是找不到符号的呢……有的折腾了。

    @cntatch 就算埋坑,有关 bug 也可能从来不被发现,直到你替他擦屁股的时候。

    @chenzhongxiang 太放水了。
    glibc 质量还是挺菜的,虽然主要是设计而不是实现问题。

    @zengmingyang96 指定个 2^4096B 试试?还有指定了就一定能留得出来?

    @dangyuluo 不管你拿多少,当务之急不是先考虑怎么把菜鸡撵走吗?
    如果这同事就是给你发钱的老板,当我没说。……就指使别人撵(

    @saberlong 显然不是。都说拒绝 getline 了。

    @forcecharlie 这不就是自己造_IOLBF 特供的丐版 ifstream 么。

    @hu8245 正解,不过最好还是有代码风格合规负责人教育什么清楚事情应该什么人管。
    dangyuluo
        25
    dangyuluo  
    OP
       2022-09-16 01:38:29 +08:00
    @FrankHB 大佬息怒。最后我用 fgets 配合自己的 stack buffer 写好了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   930 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 77ms · UTC 21:13 · PVG 05:13 · LAX 13:13 · JFK 16:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.