简体   繁体   English

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

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

So I have the following code:所以我有以下代码:

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)

Notice I did NOT delete the pointer to the window and valgrind has not detected any leaks.请注意,我没有删除指向窗口的指针,并且 valgrind 没有检测到任何泄漏。
I have searched the docs ( https://www.fltk.org/doc-1.3/basics.html ), as well as the FAQ pages ( https://www.fltk.org/doc-1.3/FAQ.html , https://www.fltk.org/articles.php ), and I've found that the most recent grouping widget automatically attaches newly created widgets, but I've found nothing about how memory is managed by fltk, as in, whether there is some "garbage collector", or if I have to delete the pointer manually.我搜索了文档( https://www.fltk.org/doc-1.3/basics.html )以及常见问题解答页面( https://www.fltk.org/doc-1.3/FAQ.htmlhttps://www.fltk.org/articles.php ),我发现最近的分组小部件会自动附加新创建的小部件,但我没有发现有关 fltk 如何管理内存的信息,例如有一些“垃圾收集器”,或者如果我必须手动删除指针。
Normally this output would imply that there is some hidden mechanism that is responsible for freeing memory as I have not manually freed the memory allocated for the window and there seems to be no leak, but take a look at the following modification to the previous code:通常这个输出意味着有一些隐藏的机制负责释放内存,因为我没有手动释放为窗口分配的内存,而且似乎没有泄漏,但请看一下对前面代码的以下修改:

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)

Now it seems that there is a memory leak.现在看来是内存泄漏了。 It appears that the font library is causing this.看来是字体库导致了这种情况。
I will again modify the code to delete the pointers to the widgets:我将再次修改代码以删除指向小部件的指针:

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)

To say the least this modification only worsened the condition XD.至少可以说,这种修改只会使病情恶化 XD。
In fact, (If I'm not mistaken) the "bad permissions for mapped region..." hints that an attempt has been made to free memory twice, which would suggest that there is indeed some memory management mechanism in fltk.事实上,(如果我没记错的话)“映射区域的错误权限......”暗示已经尝试两次释放内存,这表明 fltk 中确实存在一些内存管理机制。
But then I found this: How to fix memory leaks in simplest FLTK programm?但后来我发现了这一点: 如何在最简单的 FLTK 程序中修复内存泄漏? Which implies that I should delete the pointers so right now I feel somewhat confused :)这意味着我应该删除指针,所以现在我感到有些困惑:)
My best guess is that:我最好的猜测是:
(1) the font library is malfunctioning and (1) 字体库出现故障和
(2) FLTK has some internal garbage collector (so I shouldn't delete widget pointers manually so as not to cause any errors), can anyone confirm? (2) FLTK 有一些内部垃圾收集器(所以我不应该手动删除小部件指针以免引起任何错误),谁能确认?

This is 2/3 of the answer.这是答案的 2/3。 I'll have to try out FLTK on a Linux environment to work out the other 1/3.我必须在 Linux 环境中试用 FLTK 才能计算出其他 1/3。

FLTK will delete the child widgets when a window is deleted.当一个窗口被删除时,FLTK 将删除子部件。 If you look in the destructor of FL_DoubleWindow, it reads如果您查看 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();
}

I can't explain the second case but in the third case, the box is a child of the window and gets deleted when the window gets deleted.我无法解释第二种情况,但在第三种情况下,该框是窗口的子项,并在窗口被删除时被删除。 So when the code deletes box, it is deleting a deleted item, hence the error.因此,当代码删除框时,它正在删除已删除的项目,因此出现错误。

Valgrind logs clearly show that pointers allocated by Fl_Double_Window and new Fl_Box are not leaked, so it would not be reasonable to try and delete them manually. Valgrind 日志清楚地表明Fl_Double_Windownew Fl_Box分配的指针没有泄漏,因此尝试手动delete它们是不合理的。

The font library has a "leak";字体库有“泄漏”; is designed to work this way.旨在以这种方式工作。 Whether it is a good design or not is debatable, but this is the design.它是否是一个好的设计是有争议的,但这就是设计。 When it loads a font, it leaves it there until the application finishes.当它加载一个字体时,它会留在那里直到应用程序完成。 The application can use any font at any moment.该应用程序可以随时使用任何字体。 There is no good place to free fonts, other than at application exit, and application exit clears everything up anyway.除了在应用程序退出时,没有什么地方可以释放字体,而且应用程序退出会清除所有内容。 An application is unlikely to use a billion different fonts (more likely 3 to 10) so there is no risk of filling the memory with unused fonts.应用程序不太可能使用十亿种不同的字体(更有可能是 3 到 10 种),因此不存在用未使用的字体填充内存的风险。 If your application does use a billion different fonts, you better find a way to cache them reasonably according to your application needs;如果您的应用程序确实使用了 10 亿种不同的字体,那么您最好根据应用程序的需要找到一种合理缓存它们的方法; a simple font library is unlikely to do a good job of it.一个简单的字体库不太可能做好。

Exhibit A .图表 A。

But have you managed to find out where the outermost widgets get deleted?但是您是否设法找出最外面的小部件被删除的位置? In this case the Fl_Double_Window.在本例中为 Fl_Double_Window。

FLTK does not delete such outermost widgets - usually windows - by itself. FLTK 不会自行删除此类最外面的小部件(通常是窗口)。 Such widgets are deleted when they go out of scope (if allocated on the stack) or by using operator delete (which is the programmer's responsibility).当这些小部件超出范围(如果在堆栈上分配)或使用操作符删除(这是程序员的责任)时,它们会被删除。

I just tried recompiling all three situations (with the -O0 -g ops) and running valgrind: creating an Fl_Double_Window on the stack (leak free), creating an Fl_Double_Window on the heap and not deleting it (leak free), and finally, creating an Fl_Double_Window on the heap and deleting it (leak free).我只是尝试重新编译所有三种情况(使用 -O0 -g 操作)并运行 valgrind:在堆栈上创建一个 Fl_Double_Window(无泄漏),在堆上创建一个 Fl_Double_Window 并且不删除它(无泄漏),最后,创建堆上的 Fl_Double_Window 并将其删除(无泄漏)。

As someone else noted valgrind shows you the status right before the program exits.正如其他人指出的那样,valgrind 会在程序退出之前向您显示状态。 valgrind says among others "still reachable: 741,252 bytes in 1,107 blocks" in the OP's message and "Reachable blocks (those to which a pointer was found) are not shown" which means that in case 2 (on the heap) valgrind doesn't report a "leak" because there's still a pointer that points at the window. valgrind 在 OP 的消息中说“仍然可以访问:1,107 个块中的 741,252 个字节”和“未显示可访问块(找到指针的那些)”,这意味着在情况 2(在堆上)valgrind 没有报告“泄漏”,因为仍然有一个指向窗口的指针。

Deleting the window (case 3) doesn't change much because it is done right before the program ends and it would release allocated memory anyway.删除窗口(情况 3)不会有太大变化,因为它是在程序结束之前完成的,无论如何它都会释放分配的内存。 The difference is only that using delete runs the destructors which means that other resources can be freed (buffered data can be written, files can be closed or deleted, etc.).区别仅在于使用delete运行析构函数,这意味着可以释放其他资源(可以写入缓冲数据,可以关闭或删除文件等)。

Whether something should be considered a leak depends on the behavior during runtime.是否应该将某些内容视为泄漏取决于运行时的行为。 If your program often allocates windows and widgets on the heap and doesn't delete them, then this constitutes a memory leak (but that's not FLTK's fault then).如果您的程序经常在堆上分配窗口和小部件并且不删除它们,那么这构成了内存泄漏(但这不是 FLTK 的错)。 FLTK guarantees that all child widgets of eg a window are deleted when the parent window is deleted. FLTK 保证当父窗口被删除时,例如一个窗口的所有子窗口部件都被删除。 That's all.就这样。 There is no garbage collector running in the background.没有垃圾收集器在后台运行。

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

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