繁体   English   中英

我是否必须删除指向 FLTK 中小部件的指针?

[英]Do I have to delete pointers to widgets in FLTK?

所以我有以下代码:

int main(int, char **) {
    auto wptr = new Fl_Double_Window{640,480};
    wptr->show();
    Fl::run();
    return 0;
}
> valgrind --leak-check=full -s ./run
==13685== Memcheck, a memory error detector
==13685== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==13685== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==13685== Command: ./run
==13685==
==13685==
==13685== HEAP SUMMARY:
==13685==     in use at exit: 741,252 bytes in 1,107 blocks
==13685==   total heap usage: 14,853 allocs, 13,746 frees, 2,829,612 bytes allocated
==13685==
==13685== LEAK SUMMARY:
==13685==    definitely lost: 0 bytes in 0 blocks
==13685==    indirectly lost: 0 bytes in 0 blocks
==13685==      possibly lost: 0 bytes in 0 blocks
==13685==    still reachable: 741,252 bytes in 1,107 blocks
==13685==         suppressed: 0 bytes in 0 blocks
==13685== Reachable blocks (those to which a pointer was found) are not shown.
==13685== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==13685==
==13685== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
--13685--
--13685-- used_suppression:      1 X on SUSE11 writev uninit padding /usr/lib/valgrind/default.supp:377
==13685==
==13685== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

请注意,我没有删除指向窗口的指针,并且 valgrind 没有检测到任何泄漏。
我搜索了文档( https://www.fltk.org/doc-1.3/basics.html )以及常见问题解答页面( https://www.fltk.org/doc-1.3/FAQ.htmlhttps://www.fltk.org/articles.php ),我发现最近的分组小部件会自动附加新创建的小部件,但我没有发现有关 fltk 如何管理内存的信息,例如有一些“垃圾收集器”,或者如果我必须手动删除指针。
通常这个输出意味着有一些隐藏的机制负责释放内存,因为我没有手动释放为窗口分配的内存,而且似乎没有泄漏,但请看一下对前面代码的以下修改:

int main(int, char **) {
    auto wptr = new Fl_Double_Window{640,480};
    auto box = new Fl_Box{0,0,100,100,"Hello!"}; // Adding widget
    wptr->show();
    Fl::run();
    return 0;
}
valgrind --leak-check=full -s ./run
==14005== Memcheck, a memory error detector
==14005== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==14005== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==14005== Command: ./run
==14005==
==14005==
==14005== HEAP SUMMARY:
==14005==     in use at exit: 1,101,954 bytes in 11,185 blocks
==14005==   total heap usage: 31,631 allocs, 20,446 frees, 7,013,742 bytes allocated
==14005==
==14005== 384 (256 direct, 128 indirect) bytes in 1 blocks are definitely lost in loss record 368 of 540
==14005==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
==14005==    by 0x4EC8255: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14005==    by 0x4ECC200: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14005==    by 0x4D433BF: ??? (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4D438F5: ??? (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4D43C96: ??? (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4D44080: XftDefaultHasRender (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4D44558: XftDefaultSubstitute (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4D46FD3: XftFontMatch (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4B30739: Fl_Font_Descriptor::Fl_Font_Descriptor(char const*, int, int) (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4B309F2: ??? (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4B337BB: fl_normal_label(Fl_Label const*, int, int, int, int, unsigned int) (in /usr/lib/libfltk.so.1.3.7)
==14005==
==14005== 2,565 (768 direct, 1,797 indirect) bytes in 1 blocks are definitely lost in loss record 482 of 540
==14005==    at 0x484383F: realloc (vg_replace_malloc.c:1192)
==14005==    by 0x4EC830E: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14005==    by 0x4ED94DA: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14005==    by 0x4ED156C: FcFontRenderPrepare (in /usr/lib/libfontconfig.so.1.12.0)
==14005==    by 0x4ED1B9D: FcFontMatch (in /usr/lib/libfontconfig.so.1.12.0)
==14005==    by 0x4D46FEF: XftFontMatch (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4B30739: Fl_Font_Descriptor::Fl_Font_Descriptor(char const*, int, int) (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4B309F2: ??? (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4B337BB: fl_normal_label(Fl_Label const*, int, int, int, int, unsigned int) (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4B3390A: Fl_Widget::draw_label(int, int, int, int, unsigned int) const (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4AD8D70: Fl_Group::draw_child(Fl_Widget&) const (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4AD8F92: Fl_Group::draw_children() (in /usr/lib/libfltk.so.1.3.7)
==14005==
==14005== LEAK SUMMARY:
==14005==    definitely lost: 1,024 bytes in 2 blocks
==14005==    indirectly lost: 1,925 bytes in 69 blocks
==14005==      possibly lost: 0 bytes in 0 blocks
==14005==    still reachable: 1,099,005 bytes in 11,114 blocks
==14005==         suppressed: 0 bytes in 0 blocks
==14005== Reachable blocks (those to which a pointer was found) are not shown.
==14005== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==14005==
==14005== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 1 from 1)
--14005--
--14005-- used_suppression:      1 X on SUSE11 writev uninit padding /usr/lib/valgrind/default.supp:377
==14005==
==14005== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 1 from 1)

现在看来是内存泄漏了。 看来是字体库导致了这种情况。
我将再次修改代码以删除指向小部件的指针:

int main(int, char **) {
    auto wptr = new Fl_Double_Window{640,480};
    auto box = new Fl_Box{0,0,100,100,"Hello!"};
    wptr->show();
    Fl::run();
    delete wptr;
    delete box;
    return 0;
}
> valgrind --leak-check=full ./run
==14238== Memcheck, a memory error detector
==14238== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==14238== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==14238== Command: ./run
==14238==
==14238== Invalid read of size 8
==14238==    at 0x1091CA: main (main.cpp:64)
==14238==  Address 0x58a8730 is 0 bytes inside a block of size 120 free'd
==14238==    at 0x48419AB: operator delete(void*, unsigned long) (vg_replace_malloc.c:814)
==14238==    by 0x4AD862D: Fl_Group::clear() (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4AD86E7: Fl_Group::~Fl_Group() (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4AD1889: Fl_Double_Window::~Fl_Double_Window() (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x1091C0: main (main.cpp:63)
==14238==  Block was alloc'd at
==14238==    at 0x483EF3F: operator new(unsigned long) (vg_replace_malloc.c:417)
==14238==    by 0x10915F: main (main.cpp:60)
==14238==
==14238== Jump to the invalid address stated on the next line
==14238==    at 0x0: ???
==14238==    by 0x51D4B24: (below main) (in /usr/lib/libc-2.33.so)
==14238==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==14238==
==14238==
==14238== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==14238==  Bad permissions for mapped region at address 0x0
==14238==    at 0x0: ???
==14238==    by 0x51D4B24: (below main) (in /usr/lib/libc-2.33.so)
==14238==
==14238== HEAP SUMMARY:
==14238==     in use at exit: 1,156,045 bytes in 11,490 blocks
==14238==   total heap usage: 31,586 allocs, 20,096 frees, 7,058,062 bytes allocated
==14238==
==14238== 80 bytes in 1 blocks are possibly lost in loss record 277 of 558
==14238==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
==14238==    by 0x53E6D37: ??? (in /usr/lib/libGLdispatch.so.0.0.0)
==14238==    by 0x53E73EE: __glDispatchInit (in /usr/lib/libGLdispatch.so.0.0.0)
==14238==    by 0x54600AA: ??? (in /usr/lib/libGLX.so.0.0.0)
==14238==    by 0x400FE2D: call_init (in /usr/lib/ld-2.33.so)
==14238==    by 0x400FF1B: _dl_init (in /usr/lib/ld-2.33.so)
==14238==    by 0x40010C9: ??? (in /usr/lib/ld-2.33.so)
==14238==
==14238== 80 bytes in 1 blocks are possibly lost in loss record 278 of 558
==14238==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
==14238==    by 0x53E6D37: ??? (in /usr/lib/libGLdispatch.so.0.0.0)
==14238==    by 0x53E75D3: __glDispatchRegisterStubCallbacks (in /usr/lib/libGLdispatch.so.0.0.0)
==14238==    by 0x538E076: ??? (in /usr/lib/libOpenGL.so.0.0.0)
==14238==    by 0x400FE2D: call_init (in /usr/lib/ld-2.33.so)
==14238==    by 0x400FF1B: _dl_init (in /usr/lib/ld-2.33.so)
==14238==    by 0x40010C9: ??? (in /usr/lib/ld-2.33.so)
==14238==
==14238== 80 bytes in 1 blocks are possibly lost in loss record 279 of 558
==14238==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
==14238==    by 0x53E6D37: ??? (in /usr/lib/libGLdispatch.so.0.0.0)
==14238==    by 0x53E75D3: __glDispatchRegisterStubCallbacks (in /usr/lib/libGLdispatch.so.0.0.0)
==14238==    by 0x4A22076: ??? (in /usr/lib/libGL.so.1.7.0)
==14238==    by 0x400FE2D: call_init (in /usr/lib/ld-2.33.so)
==14238==    by 0x400FF1B: _dl_init (in /usr/lib/ld-2.33.so)
==14238==    by 0x40010C9: ??? (in /usr/lib/ld-2.33.so)
==14238==
==14238== 384 (256 direct, 128 indirect) bytes in 1 blocks are definitely lost in loss record 380 of 558
==14238==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
==14238==    by 0x4EC8255: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14238==    by 0x4ECC200: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14238==    by 0x4D433BF: ??? (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4D438F5: ??? (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4D43C96: ??? (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4D44080: XftDefaultHasRender (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4D44558: XftDefaultSubstitute (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4D46FD3: XftFontMatch (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4B30739: Fl_Font_Descriptor::Fl_Font_Descriptor(char const*, int, int) (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4B309F2: ??? (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4B337BB: fl_normal_label(Fl_Label const*, int, int, int, int, unsigned int) (in /usr/lib/libfltk.so.1.3.7)
==14238==
==14238== 2,565 (768 direct, 1,797 indirect) bytes in 1 blocks are definitely lost in loss record 498 of 558
==14238==    at 0x484383F: realloc (vg_replace_malloc.c:1192)
==14238==    by 0x4EC830E: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14238==    by 0x4ED94DA: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14238==    by 0x4ED156C: FcFontRenderPrepare (in /usr/lib/libfontconfig.so.1.12.0)
==14238==    by 0x4ED1B9D: FcFontMatch (in /usr/lib/libfontconfig.so.1.12.0)
==14238==    by 0x4D46FEF: XftFontMatch (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4B30739: Fl_Font_Descriptor::Fl_Font_Descriptor(char const*, int, int) (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4B309F2: ??? (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4B337BB: fl_normal_label(Fl_Label const*, int, int, int, int, unsigned int) (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4B3390A: Fl_Widget::draw_label(int, int, int, int, unsigned int) const (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4AD8D70: Fl_Group::draw_child(Fl_Widget&) const (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4AD8F92: Fl_Group::draw_children() (in /usr/lib/libfltk.so.1.3.7)
==14238==
==14238== LEAK SUMMARY:
==14238==    definitely lost: 1,024 bytes in 2 blocks
==14238==    indirectly lost: 1,925 bytes in 69 blocks
==14238==      possibly lost: 240 bytes in 3 blocks
==14238==    still reachable: 1,152,856 bytes in 11,416 blocks
==14238==         suppressed: 0 bytes in 0 blocks
==14238== Reachable blocks (those to which a pointer was found) are not shown.
==14238== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==14238==
==14238== For lists of detected and suppressed errors, rerun with: -s
==14238== ERROR SUMMARY: 7 errors from 7 contexts (suppressed: 1 from 1)
Segmentation fault (core dumped)

至少可以说,这种修改只会使病情恶化 XD。
事实上,(如果我没记错的话)“映射区域的错误权限......”暗示已经尝试两次释放内存,这表明 fltk 中确实存在一些内存管理机制。
但后来我发现了这一点: 如何在最简单的 FLTK 程序中修复内存泄漏? 这意味着我应该删除指针,所以现在我感到有些困惑:)
我最好的猜测是:
(1) 字体库出现故障和
(2) FLTK 有一些内部垃圾收集器(所以我不应该手动删除小部件指针以免引起任何错误),谁能确认?

这是答案的 2/3。 我必须在 Linux 环境中试用 FLTK 才能计算出其他 1/3。

当一个窗口被删除时,FLTK 将删除子部件。 如果您查看 FL_DoubleWindow 的析构函数,它会显示

/**
  The destructor <I>also deletes all the children</I>. This allows a
  whole tree to be deleted at once, without having to keep a pointer to
  all the children in the user code.
*/
Fl_Double_Window::~Fl_Double_Window() {
  hide();
}

我无法解释第二种情况,但在第三种情况下,该框是窗口的子项,并在窗口被删除时被删除。 因此,当代码删除框时,它正在删除已删除的项目,因此出现错误。

Valgrind 日志清楚地表明Fl_Double_Windownew Fl_Box分配的指针没有泄漏,因此尝试手动delete它们是不合理的。

字体库有“泄漏”; 旨在以这种方式工作。 它是否是一个好的设计是有争议的,但这就是设计。 当它加载一个字体时,它会留在那里直到应用程序完成。 该应用程序可以随时使用任何字体。 除了在应用程序退出时,没有什么地方可以释放字体,而且应用程序退出会清除所有内容。 应用程序不太可能使用十亿种不同的字体(更有可能是 3 到 10 种),因此不存在用未使用的字体填充内存的风险。 如果您的应用程序确实使用了 10 亿种不同的字体,那么您最好根据应用程序的需要找到一种合理缓存它们的方法; 一个简单的字体库不太可能做好。

图表 A。

但是您是否设法找出最外面的小部件被删除的位置? 在本例中为 Fl_Double_Window。

FLTK 不会自行删除此类最外面的小部件(通常是窗口)。 当这些小部件超出范围(如果在堆栈上分配)或使用操作符删除(这是程序员的责任)时,它们会被删除。

我只是尝试重新编译所有三种情况(使用 -O0 -g 操作)并运行 valgrind:在堆栈上创建一个 Fl_Double_Window(无泄漏),在堆上创建一个 Fl_Double_Window 并且不删除它(无泄漏),最后,创建堆上的 Fl_Double_Window 并将其删除(无泄漏)。

正如其他人指出的那样,valgrind 会在程序退出之前向您显示状态。 valgrind 在 OP 的消息中说“仍然可以访问:1,107 个块中的 741,252 个字节”和“未显示可访问块(找到指针的那些)”,这意味着在情况 2(在堆上)valgrind 没有报告“泄漏”,因为仍然有一个指向窗口的指针。

删除窗口(情况 3)不会有太大变化,因为它是在程序结束之前完成的,无论如何它都会释放分配的内存。 区别仅在于使用delete运行析构函数,这意味着可以释放其他资源(可以写入缓冲数据,可以关闭或删除文件等)。

是否应该将某些内容视为泄漏取决于运行时的行为。 如果您的程序经常在堆上分配窗口和小部件并且不删除它们,那么这构成了内存泄漏(但这不是 FLTK 的错)。 FLTK 保证当父窗口被删除时,例如一个窗口的所有子窗口部件都被删除。 就这样。 没有垃圾收集器在后台运行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM