GNOME Bugzilla – Bug 651247
Cannot get Goocanvas::Polyline constructor with Points argument to work.
Last modified: 2011-06-03 18:38:23 UTC
I'm confused about the correct use of Polyline in Goocanvasmm 2.0. The following points = new Goocanvas::Points(STRIP_MAX_LENGTH); line = Goocanvas::Polyline::create(false, *points); gives a segmentation fault on the second line, complaining about the Polyline operator= Points and line are declared as: Goocanvas::Points *points; Glib::RefPtr<Goocanvas::Polyline> line; I cannot find any example for Goocanvasmm 2.0 Polylines with non-single-line creation. A demo program available on the 'net comments out that mode and instead instantiates all line segments line-by-line: http://www.google.com/codesearch/p?hl=en#vaS0EaWX668/examples/demo/primitives.cc&q=Goocanvas::Polyline::create&d=2 which seems to indicate some problem with Polylines... Can anyone help me out here? Preferable with a pointer to a working example?
The example code you link to is probably the demo example in goocanvasmm, http://git.gnome.org/browse/goocanvasmm/tree/examples/demo I uncommented this code in primitives.cc /* Glib::RefPtr<Goocanvas::Points> points = Goocanvas::Points::create(4); points->set_coordinate(0, 340, 170); points->set_coordinate(1, 340, 230); points->set_coordinate(2, 390, 230); points->set_coordinate(3, 390, 170); line = Goocanvas::Polyline::create(false, points); root->add_child(line); */ then changed it so it compiles Goocanvas::Points* points = new Goocanvas::Points(4); points->set_coordinate(0, 340, 170); points->set_coordinate(1, 340, 230); points->set_coordinate(2, 390, 230); points->set_coordinate(3, 390, 170); line = Goocanvas::Polyline::create(false, *points); root->add_child(line); I can run the modified program without a segmentation fault. The extra polyline is written. I've used the latest source code from the Git repository for goocanvasmm, goocanvas, gtkmm, etc. Can you please supply a small test case that shows the bug you've found. Or check if a suitably modified demo example crashes on the version of goocanvasmm that you use.
> then changed it so it compiles > > Goocanvas::Points* points = new Goocanvas::Points(4); > points->set_coordinate(0, 340, 170); > points->set_coordinate(1, 340, 230); > points->set_coordinate(2, 390, 230); > points->set_coordinate(3, 390, 170); > line = Goocanvas::Polyline::create(false, *points); > root->add_child(line); Hello Kjell, My apologies for the delay in responding. I hadn't changed the demo to test it, but the code I used in my program was very similar: channel[chan_nr].points = new Goocanvas::Points(STRIP_MAX_LENGTH); channel[chan_nr].line = Goocanvas::Polyline::create(false, *channel[chan_nr].points); I get the segfault in the second line. The complete code is very short, so I'll add it as an attachment. John
Created attachment 189058 [details] Test case
I can't run your test case without file src/ejemplo1.ui. main.cc also includes config.h. Is that file also necessary, or can I just remove '#include "config.h"'? The program compiles, if I do that.
I still haven't been able to run your program up until the segmentation fault, but I studied your code, and I think I know what's the problem. You allocate memory with realloc(), which returns uninitialized memory. channel = (Channel *) realloc(channel, nr_channels * sizeof(Channel)); 'channel' is a pointer to the struct typedef struct { double min, max, actual; Goocanvas::Points *points; Glib::RefPtr<Goocanvas::ItemSimple> line; } Channel; When you allocate memory this way, the constructor of Channel::line is not executed. Glib::RefPtr contains a pointer, which is not cleared. When you assign to Channel::line, Glib::RefPtr tries to access the object pointed to by the uninitialized pointer, if it's not 0. You could save your program by clearing the newly allocated memory with memset(), but it's a bad idea. You should allocate memory for C++ objects in such a way that their constructors are executed.
Created attachment 189083 [details] UI file for project Thanks for looking at the code! I'll add the config.h too, though it's probably not necessary for this simple case. Yes, I read about the uninitialized memory from realloc. But isn't that the case for any C++ variable declaration? The demo example also declares Glib::RefPtr<Goocanvas::ItemSimple> line; without assigning any value. I'm not entirely clear on the function of the RefPtr, but would this be the same case? According to http://www.intap.net/~drw/cpp/cpp03_02.htm: "In some languages, variables are initialized to 0 - that is, a variable's initial value will be 0. This is not true of C++! " I had already tried to use 'new' with the polyline, but the constructor is declared protected, so that doesn't work - create seems the only way.
Created attachment 189084 [details] config.h
(In reply to comment #6) > The demo example also declares > > Glib::RefPtr<Goocanvas::ItemSimple> line; > > without assigning any value. I'm not entirely clear on the function of the > RefPtr, but would this be the same case? No, it's not the same case. When you declare 'line' like this as a local variable on the stack, its default constructor is executed. Glib::RefPtr contains the pointer T_CppObject* pCppObject_; and its default constructor clears that pointer: template <class T_CppObject> inline RefPtr<T_CppObject>::RefPtr() : pCppObject_ (0) {} realloc() is a C function. It knows nothing about C++ constructors. > I had already tried to use 'new' with the polyline, but the constructor is > declared protected, so that doesn't work - create seems the only way. Yes, create() is only way, and the correct way. The error is that Channel::line has not been correctly initialized when you assign to it. RefPtr's assignment operator checks if it already points to another Goocanvas::ItemSimple, and if it does, it unreferences that object. In your case, the pointer in RefPtr is not null, but it does not contain a valid pointer. I changed the declaration of StripPlot::channel to std::vector<Channel> channel; and replaced channel = (Channel *) realloc(channel, nr_channels * sizeof(Channel)); by channel.push_back(Channel()); Then there is no segmentation fault. There are of course other possibilities. The important thing is that you create each new Channel object in such a way that its constructor is executed.
Hello Kjell, It seems I still have a long way to go with C++ programming (that's a good thing - no boredom in sight). Thanks for explaining this, and I think I'm starting to understand the issue. Is there any literature on the subject of RefPtrs, Proxies, and other such exotic functions? I did quite a bit of searching, but didn't find much except for the Doxygen-generated reference information, which isn't exactly educational. I do feel there is quite a learning curve to using the 'mm' libraries, and somewhat above the knowledge level of average C++ programmers. Thanks for your patience! John
(In reply to comment #9) > Is there any literature on the subject of RefPtrs, Proxies, and other > such exotic functions? If you haven't read "Programming with gtkmm", you should read it. It's available at http://developer.gnome.org/gtkmm-tutorial/. Appendix A discusses RefPtr. Signal proxies are mentioned in Appendix B. Hope you don't mind that I change this bug's resolution from FIXED to NOTABUG. It's not a bug in goocanvasmm or glibmm or any other mm module.
Thanks again, Kjell! I'll try to download that tutorial, but I must have had bad luck, because previous times (and now too), I couldn't get at it. The browser keeps staring at a blank page till it times out (Firefox 4.0) > Hope you don't mind that I change this bug's resolution from FIXED to NOTABUG. > It's not a bug in goocanvasmm or glibmm or any other mm module. Of course I don't mind - I hadn't noticed that possibility. Cheers, John