GObject object instantiation problem
Hi, I'm currently having some problems allocating GObjects. I just added a class called SPPoint [0]. When I try to instantiate an object of that type (whether through SPObject/sp_object_child_added or manually from GDB using g_object_new does not matter), g_object_new returns an GObject* that contains a zero class: {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0} (this is not good as it breaks everything else about G_OBJECT). I was able to track down the problem to g_type_create_instance returning that when passed the new SPPoint type:
(gdb) print sp_object_get_type() $13 = 20593552 (gdb) print sp_point_get_type() $14 = 20619024 (gdb) print *((GObject*)g_type_create_instance(sp_point_get_type())) $20 = {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0} (gdb) print *((GObject*)g_type_create_instance(sp_object_get_type())) $21 = {g_type_instance = {g_class = 0x16ec560}, ref_count = 1, qdata = 0x0}
I'm currently building a glib with debugging symbols to further track down this problem. If anybody here has an idea about what might be the cause of this problem, your suggestions will likely be tremendously useful since I'm already pondering over this for a few hours. The code can be found at [1].
Thanks, Sebastian
[0] https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/view/head:/src/sp... [1] https://code.launchpad.net/~h-e-6/inkscape/connector-wip
On Jul 30, 2013, at 2:50 PM, Sebastian Götte wrote:
Hi, I'm currently having some problems allocating GObjects. I just added a class called SPPoint [0]. When I try to instantiate an object of that type (whether through SPObject/sp_object_child_added or manually from GDB using g_object_new does not matter), g_object_new returns an GObject* that contains a zero class: {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0} (this is not good as it breaks everything else about G_OBJECT). I was able to track down the problem to g_type_create_instance returning that when passed the new SPPoint type:
That might fall into the realm of places we prefer to use C++ classes instead of C-based GObject objects. Remember, the entire GObject system was implemented because C has no native object types and hierarchy support. (One interesting side-effect of past projects to convert more of our internals to C++ was to speed up performance at the same time that the architecture was cleaned up and modernized).
If it does need to be a GObject based type, then you might be missing something in the class or instance init functions.
On 07/31/2013 08:43 AM, Jon Cruz wrote:
On Jul 30, 2013, at 2:50 PM, Sebastian Götte wrote:
Hi, I'm currently having some problems allocating GObjects. I just added a class called SPPoint [0]. When I try to instantiate an object of that type (whether through SPObject/sp_object_child_added or manually from GDB using g_object_new does not matter), g_object_new returns an GObject* that contains a zero class: {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0} (this is not good as it breaks everything else about G_OBJECT). I was able to track down the problem to g_type_create_instance returning that when passed the new SPPoint type:
That might fall into the realm of places we prefer to use C++ classes instead of C-based GObject objects. Remember, the entire GObject system was implemented because C has no native object types and hierarchy support. (One interesting side-effect of past projects to convert more of our internals to C++ was to speed up performance at the same time that the architecture was cleaned up and modernized).
I need to use GObject here since this new class is part of the SPObject tree. I don't even have control about instantiating it myself, instead I create an SVG node and the whole instantiation is handled by some part of SPObject.
If it does need to be a GObject based type, then you might be missing something in the class or instance init functions.
I will have a look at it but I am pretty sure I did those right.
Thanks, jaseg
On Wed, 2013-07-31 at 11:02 +0200, Sebastian Götte wrote:
On 07/31/2013 08:43 AM, Jon Cruz wrote:
On Jul 30, 2013, at 2:50 PM, Sebastian Götte wrote:
Hi, I'm currently having some problems allocating GObjects. I just added a class called SPPoint [0]. When I try to instantiate an object of that type (whether through SPObject/sp_object_child_added or manually from GDB using g_object_new does not matter), g_object_new returns an GObject* that contains a zero class: {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0} (this is not good as it breaks everything else about G_OBJECT). I was able to track down the problem to g_type_create_instance returning that when passed the new SPPoint type:
That might fall into the realm of places we prefer to use C++ classes instead of C-based GObject objects. Remember, the entire GObject system was implemented because C has no native object types and hierarchy support. (One interesting side-effect of past projects to convert more of our internals to C++ was to speed up performance at the same time that the architecture was cleaned up and modernized).
I need to use GObject here since this new class is part of the SPObject tree. I don't even have control about instantiating it myself, instead I create an SVG node and the whole instantiation is handled by some part of SPObject.
If it does need to be a GObject based type, then you might be missing something in the class or instance init functions.
I will have a look at it but I am pretty sure I did those right.
Thanks, jaseg
I am not really sure that using "Shiny C++" code is the way to go here. At some point, it would be nice to convert all the sp-xxx files to proper C++, removing the dependency on GObject. But having one class being done differently (via GMEMWRAP) doesn't seem to bring much benefit.
Jon, perhaps you can comment further. Sebastian's code can be seen at:
https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/files
The specific files are:
https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/view/head:/src/sp... https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/view/head:/src/sp... https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/view/head:/src/go...
Tav
On Jul 31, 2013, at 2:25 AM, Tavmjong Bah wrote:
I am not really sure that using "Shiny C++" code is the way to go here. At some point, it would be nice to convert all the sp-xxx files to proper C++, removing the dependency on GObject. But having one class being done differently (via GMEMWRAP) doesn't seem to bring much benefit.
Jon, perhaps you can comment further. Sebastian's code can be seen at:
https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/files
The specific files are:
https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/view/head:/src/sp... https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/view/head:/src/sp... https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/view/head:/src/go...
Well, yes first off the use of 'new' on the SPPoint is the immediate problem.
This also looks like a place where the pimpl idiom (private implementation) can be quite helpful. This addresses the issue with 'new', and improves encapsulation. It also happens to fall in line with the major change in direction that was taken for GTK+ 3.x.
It moves the members and methods into a private helper class that exists only in the implementation .cpp file and not in the public header .h file.
First looking at sp-point.h, I see a minor bit of cleanup that is needed:
class SPPoint : public SPItem { sigc::signal<void, SPPoint*, Geom::Point> _moved_signal;
SVGLength _x, _y;
public: ~SPPoint(){} ... };
In general, we would want to start a c++ class declaration with a single 'public:' followed optionally by a single 'protected:' section and finally an optional 'private:' section. Also, for a destructor we very often need it to be virtual. Of course, with C-based GTK+ style GObjects we can't really have that... but the pimpl idiom will fix it for us.
The other major style issue is collapsing multiple variable declarations to a single line. This can lead to many subtle problems, and in the past was initially done to save space on VT100 terminals and paper printouts. We don't really need to accommodate those any more. However, a more important factor is that keeping declarations to their own lines makes for easier maintenance, better legibility, easier tracking in source control, etc.
So a first cut would change to: class SPPoint : public SPItem { public: ~SPPoint(){}
... private: sigc::signal<void, SPPoint*, Geom::Point> _moved_signal;
SVGLength _x; SVGLength _y; };
Then we want to get rid of any function bodies in the header, as that locks us into promising a certain implementation. We want to hide the details inside of the .cpp and not let anyone know what is going on: class SPPoint : public SPItem { public: ~SPPoint();
... private: sigc::signal<void, SPPoint*, Geom::Point> _moved_signal;
SVGLength _x; SVGLength _y; };
Now to apply the magic of the pimpl idiom:
class SPPointImpl;
class SPPoint : public SPItem { friend class SPPointImpl; public:
... private: SPPointImpl *_impl; };
Suddenly the private section only contains a single pointer... and that is a type that is trivially handled by a C based GObject init function. It also hides all details such as member variables, signals, etc. This latter encapsulation is following C++ OO principals and as mentioned before is in line with the changes to GKT+ itself.
The init can now be void sp_point_init(SPPoint *point) { _impl = new SPPointImpl(point); }
And individual public member functions can be delegated to the private implementation:
char* SPPoint::description() const { return _impl->description(); } (noting that returning char* is not a good API, but that is something existing that we are not addressing in this pass)
And we can always have a few options with the implementation hooking:
Geom::Point SPPoint::getPosition(void) const { /* FIXME throw this through i2doc_affine() ? */ return Geom::Point(_impl->_x.computed, _impl->_y.computed); }
or
Geom::Point SPPoint::getPosition(void) const { return _impl->getPosition(); }
Of course, using the latter will keep things consistent and more centralized.
By the way, the "SP" of "SPPoint" is something we want to avoid for any new classes. That stands for "SodiPodi" which was the project Inkscape was forked from years ago.
Oh, and as far as the wrapping from GMEMWRAP, using a pimpl class can replace that thusly:
class SPPointImpl { public: static release(SPPoint *point) { point->release(); } // or: // static release(SPPoint *point) { // delete point->_impl; // point->_impl = 0; //}
static Geom::OptRect bbox(SPPoint *point, Geom::Affine const &transform, SPItem::BBoxType type) { return point->bbox(); } ... };
static void sp_point_class_init(SPPointClass *klass) { SPObjectClass *sp_object_class = SP_OBJECT_CLASS(klass); SPItemClass *sp_item_class = SP_ITEM_CLASS(klass);
sp_object_class->release = SPPointImpl::release; sp_object_class->set = SPPointImpl::setAttr; sp_object_class->write = SPPointImpl::write; sp_item_class->bbox = SPPointImpl::bbox; sp_item_class->description = SPPointImpl::description;
2013/8/1 Jon Cruz <jon@...18...>:
This also looks like a place where the pimpl idiom (private implementation) can be quite helpful. This addresses the issue with 'new', and improves encapsulation. It also happens to fall in line with the major change in direction that was taken for GTK+ 3.x. It moves the members and methods into a private helper class that exists only in the implementation .cpp file and not in the public header .h file.
Please don't. Unless there is a reason to keep a stable ABI, and in the case of internal Inkscape objects there is none, pimpl is just gratuitous obfuscation.
For example, if you want to add a new private function to a pimpl class, you have three choices:
1) add in to the impl object, in which case your functions are in two different objects depending on their access control - if later you want to convert a private function into a public one, you have to rewrite all member accesses. 2) add it on the public object, in which case any gain in compilation speed from avoided header changes is negated. 3) make the public object purely virtual.
Let's say you then want to then add a new public function. If you choise 1) or 2), you can add it and implement it on the public object. If you chose 3), you have to make two functions: a virtual shim on the public object and the real method on the private object.
The pimpl idiom introduces conceptual, coding and runtime overhead and does not provide any significant advantage if there is no stable ABI to keep.
In general, we would want to start a c++ class declaration with a single 'public:' followed optionally by a single 'protected:' section and finally an optional 'private:' section. Also, for a destructor we very often need it to be virtual. Of course, with C-based GTK+ style GObjects we can't really have that... but the pimpl idiom will fix it for us.
The destructor is automatically virtual when the base class destructor is virtual. This will be fixed once Markus's branch is merged.
Then we want to get rid of any function bodies in the header, as that locks us into promising a certain implementation. We want to hide the details inside of the .cpp and not let anyone know what is going on:
If you put the body of a class member function in a header, it is equivalent to putting it in a .cpp file, except the function is automatically marked as inline. Putting the function body in the header does not lock us into anything, since this is an internal Inkscape object and does not have a stable ABI.
By the way, the "SP" of "SPPoint" is something we want to avoid for any new classes. That stands for "SodiPodi" which was the project Inkscape was forked from years ago.
The SP prefix should be kept for the time being, for the sake of consistency. Removing it should be a separate task.
Regards, Krzysztof
On Aug 1, 2013, at 4:03 AM, Krzysztof Kosiński wrote:
Then we want to get rid of any function bodies in the header, as that locks us into promising a certain implementation. We want to hide the details inside of the .cpp and not let anyone know what is going on:
If you put the body of a class member function in a header, it is equivalent to putting it in a .cpp file, except the function is automatically marked as inline. Putting the function body in the header does not lock us into anything, since this is an internal Inkscape object and does not have a stable ABI.
There are actually many issues here with bodies in headers. A stable ABI is just a minor one. A very important factor is compilation and development time. If a method body is in a header and needs to be changed, then every single .cpp that includes the header or that includes some other .cpp file that includes something else that eventually includes that first header will be recompiled. Keeping the headers clean also improves base compile times, as less processing is done when the fie is included or pulled in elsewhere where inclusion is needed.
Another general problem with bodies in headers is that if they are not trivial then they need to pull in other includes to be able to do their job. That 'contaminates' consumer .cpp files with more includes than absolutely necessary. Compile times for the project then go up.
By the way, the "SP" of "SPPoint" is something we want to avoid for any new classes. That stands for "SodiPodi" which was the project Inkscape was forked from years ago.
The SP prefix should be kept for the time being, for the sake of consistency. Removing it should be a separate task.
Yes... I was explicitly calling out to not *add* to new classes (hence my inclusion of "for any new classes")... not for removing it if it already was present.
On 1-8-2013 19:09, Jon Cruz wrote:
On Aug 1, 2013, at 4:03 AM, Krzysztof Kosiński wrote:
Then we want to get rid of any function bodies in the header, as that locks us into promising a certain implementation. We want to hide the details inside of the .cpp and not let anyone know what is going on:
I disagree with getting rid of /any/ function bodies in the header.
If you put the body of a class member function in a header, it is equivalent to putting it in a .cpp file, except the function is automatically marked as inline. Putting the function body in the header does not lock us into anything, since this is an internal Inkscape object and does not have a stable ABI.
There are actually many issues here with bodies in headers. A stable ABI is just a minor one. A very important factor is compilation and development time. If a method body is in a header and needs to be changed, then every single .cpp that includes the header or that includes some other .cpp file that includes something else that eventually includes that first header will be recompiled. Keeping the headers clean also improves base compile times, as less processing is done when the fie is included or pulled in elsewhere where inclusion is needed.
Another general problem with bodies in headers is that if they are not trivial [...]
The example we are discussing is ~SPPoint(){} that's as trivial as you can get, and so no need to argue about non-trivial functions. I think is very nice if simple functions like that are written inside the header. Saves some time wading through lengthy .cpp files only to find an almost empty function. If a function only has a return .........; statement, it is nice to see that in the header. There is emphasis on compilation time in your argument, but developer reading time is also important.
By the way, the "SP" of "SPPoint" is something we want to avoid for any new classes. That stands for "SodiPodi" which was the project Inkscape was forked from years ago.
The SP prefix should be kept for the time being, for the sake of consistency. Removing it should be a separate task.
Yes... I was explicitly calling out to not *add* to new classes (hence my inclusion of "for any new classes")... not for removing it if it already was present.
And Krzysztof was explicitly calling out to *add* it to new classes that have a similar function as the other SPFriends, with which I fully agree.
On Aug 1, 2013, at 10:34 AM, Johan Engelen wrote:
By the way, the "SP" of "SPPoint" is something we want to avoid for any new classes. That stands for "SodiPodi" which was the project Inkscape was forked from years ago.
The SP prefix should be kept for the time being, for the sake of consistency. Removing it should be a separate task.
Yes... I was explicitly calling out to not *add* to new classes (hence my inclusion of "for any new classes")... not for removing it if it already was present.
And Krzysztof was explicitly calling out to *add* it to new classes that have a similar function as the other SPFriends, with which I fully agree.
Right, and the project has discussed this a few times in the past, including discussions with Bryce, Ted, etc. As far as consistency goes, remember "A foolish consistency is the hobgoblin of little minds".
In this case, we had explicitly called out to no longer add the "SP" prefix even in areas that already had it. Adding in more instances will just make it that much harder to remove. We were called on to at least not make the problem worse.
That does lead us to a good opportunity in this case. Since if we drop the "sp" of the new name, that will leave only "Point". Now we end up with a class name that is fairly ambiguous and really needs some clarification. lib2geom has it's own 'point', and there are others. If we put back the "SP" prefix, all that really says is "the point class that happens to live in the SodiPodi codebase". Definitely not too helpful.
Reading the header indicates from the comment that this is for the SVG draft on connectors. In that draft, we have the explicit element named "point". Since Sebastian gave us such good info, we can use that to help the code. A verbose name could be "ConnectorPoint" or "PointElement". However in this case we can probably gain from the spec and since it is actually proposed as part of SVG itself we can call it "SVGPoint".
Taken in context, this would look like
SVGPoint *point = FooGetPoint(); ... Geom::Point where = point->getPosition();
*or* we could actually take advantage of consistency *and* C++ and go with a namespace (typing that previous line was a good hint to that possibility):
SVG::Point *point = FooGetPoint(); ... Geom::Point where = point->getPosition();
So that changes from SPPoint which says "The point class in the SodiPodi codebase" to SVG::Point which says "the 'point' from SVG itself". Much more informative.
On Aug 1, 2013, at 10:34 AM, Johan Engelen wrote:
The example we are discussing is ~SPPoint(){} that's as trivial as you can get, and so no need to argue about non-trivial functions. I think is very nice if simple functions like that are written inside the header. Saves some time wading through lengthy .cpp files only to find an almost empty function. If a function only has a return .........; statement, it is nice to see that in the header. There is emphasis on compilation time in your argument, but developer reading time is also important.
Well... I did say I was addressing a 'general' problem. For a coder going to *use* a class, the members should not mean anything at all. So the public API of the .h file can actually be clearer by leaving them off. If one needs to know what a function does, it's doc comment should declare it. Implementing is a different matter.
*however* in this specific case there is an even simpler solution. If we are speaking of a destructor that does nothing, we can just not declare it at all. If C++ does not see an explicit destructor, the compiler will automatically do the equivalent of ~SPPoint(){} and there is no need to explicitly add it.
2013/8/1 Jon Cruz <jon@...18...>:
Another general problem with bodies in headers is that if they are not trivial then they need to pull in other includes to be able to do their job. That 'contaminates' consumer .cpp files with more includes than absolutely necessary. Compile times for the project then go up.
This is a legitimate issue, but it is only relevant in this case:
#include <big-object.h> #include <mammoth-object.h> #include <gargantuan-object.h>
class SimpleClass { public: ... private: BigObject _x; MammothObject _y; GargantuanObject _z; };
Instead of hiding the three member objects in a pimpl, one can convert _x, _y and _z to pointers, in which case only forward declarations are necessary. This is more readable, because one doesn't need to track down the definition of the pimpl structure to know the members of the class.
Regards, Krzysztof
On Aug 1, 2013, at 6:04 PM, Krzysztof Kosiński wrote:
2013/8/1 Jon Cruz <jon@...18...>:
Another general problem with bodies in headers is that if they are not trivial then they need to pull in other includes to be able to do their job. That 'contaminates' consumer .cpp files with more includes than absolutely necessary. Compile times for the project then go up.
This is a legitimate issue, but it is only relevant in this case:
#include <big-object.h> #include <mammoth-object.h> #include <gargantuan-object.h>
class SimpleClass { public: ... private: BigObject _x; MammothObject _y; GargantuanObject _z; };
Instead of hiding the three member objects in a pimpl, one can convert _x, _y and _z to pointers, in which case only forward declarations are necessary. This is more readable, because one doesn't need to track down the definition of the pimpl structure to know the members of the class.
Actually, that's not the only relevant case.
First, even seemingly small include files can add up to measurable compile-time differences. And I've even worked on projects where enabling pre-compiled headers (a work-around designed to address just such time issues) end up making the end-to-end compile go slower instead of faster. In one case it was only about minute difference, but since it was on a compile that took under five minutes normally that ends up impacting developers.
Even this case can have a significant measured difference:
#include "forward.h"
class SimpleClass { public: ... private: int _x; int _y; int _z; };
In this case, I've seen bad headers (aka too-inclusive instead of relying on simple forward declarations) increase parse/compile time for a .cpp by an order of magnitude or two. A key point is that it doesn't matter if there are member types that are complex, only if an include happens to include another include that includes some includes that take the compiler a while to parse.
(The mention in the example of using three pointers is a completely different issue.)
On 1-8-2013 13:03, Krzysztof Kosiński wrote:
2013/8/1 Jon Cruz <jon@...18...>:
This also looks like a place where the pimpl idiom (private implementation) can be quite helpful. This addresses the issue with 'new', and improves encapsulation. It also happens to fall in line with the major change in direction that was taken for GTK+ 3.x. It moves the members and methods into a private helper class that exists only in the implementation .cpp file and not in the public header .h file.
Please don't. Unless there is a reason to keep a stable ABI, and in the case of internal Inkscape objects there is none, pimpl is just gratuitous obfuscation.
+1
On 07/31/2013 11:25 AM, Tavmjong Bah wrote:
On Wed, 2013-07-31 at 11:02 +0200, Sebastian Götte wrote:
On 07/31/2013 08:43 AM, Jon Cruz wrote:
On Jul 30, 2013, at 2:50 PM, Sebastian Götte wrote:
Hi, I'm currently having some problems allocating GObjects. I just added a class called SPPoint [0]. When I try to instantiate an object of that type (whether through SPObject/sp_object_child_added or manually from GDB using g_object_new does not matter), g_object_new returns an GObject* that contains a zero class: {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0} (this is not good as it breaks everything else about G_OBJECT). I was able to track down the problem to g_type_create_instance returning that when passed the new SPPoint type:
That might fall into the realm of places we prefer to use C++ classes instead of C-based GObject objects. Remember, the entire GObject system was implemented because C has no native object types and hierarchy support. (One interesting side-effect of past projects to convert more of our internals to C++ was to speed up performance at the same time that the architecture was cleaned up and modernized).
I need to use GObject here since this new class is part of the SPObject tree. I don't even have control about instantiating it myself, instead I create an SVG node and the whole instantiation is handled by some part of SPObject.
If it does need to be a GObject based type, then you might be missing something in the class or instance init functions.
I will have a look at it but I am pretty sure I did those right.
Thanks, jaseg
I am not really sure that using "Shiny C++" code is the way to go here. At some point, it would be nice to convert all the sp-xxx files to proper C++, removing the dependency on GObject. But having one class being done differently (via GMEMWRAP) doesn't seem to bring much benefit.
That is a valid point. I chose the C++ path since it lead to somewhat more concise code and since from a mailing list discussion a few weeks back (late march) I got the impression that this C++ification of the SPObject tree was somewhere on the roadmap for 0.49. Also, I'm just using plain C++ member functions (nothing virtual, no dynamic_cast run time type info things etc.). All of these methods could be translated more or less 1:1 to C functions and the corresponding classes still look like structs.
However I can un-shiny this code to plain C/GObject for the meantime for readability if this is too far off.
I think the GMEMWRAP macro and the template it is wrapping are a pretty good way to bridge both worlds since this really just generates a very thin static wrapper function around C++ member functions, using C++'s type system for casting (which is already used by the SPObject tree insofar as it can be used for proper casting).
Jon, perhaps you can comment further. Sebastian's code can be seen at:
https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/files
The specific files are:
https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/view/head:/src/sp... https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/view/head:/src/sp... https://bazaar.launchpad.net/~h-e-6/inkscape/connector-wip/view/head:/src/go...
Tav
Thanks, Sebastian
2013/7/30 Sebastian Götte <jaseg@...2974...>:
Hi, I'm currently having some problems allocating GObjects. I just added a class called SPPoint [0]. When I try to instantiate an object of that type (whether through SPObject/sp_object_child_added or manually from GDB using g_object_new does not matter), g_object_new returns an GObject* that contains a zero class: {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0} (this is not good as it breaks everything else about G_OBJECT). I was able to track down the problem to g_type_create_instance returning that when passed the new SPPoint type:
I think this is the problem:
static void sp_point_init(SPPoint *point){ new (point) SPPoint(); }
This will destroy parent initialization. Parent init functions which run before this one invoke the member constructors manually. In existing code, the constructor of SPObject is never called. The destructors are called manually in the dispose function. Instead of calling new, you have to construct each member separately.
Note that NRObject once contained a better solution to this problem, which automatically invoked the C++ constructor at instance init time. You can dig out nr-object.cpp and nr-object.h from source control and investigate. However, using it would require you to rewrite the init functions of all SPObjects.
Regards, Krzysztof
2013/7/31 Krzysztof Kosiński <tweenk.pl@...400...>:
Note that NRObject once contained a better solution to this problem, which automatically invoked the C++ constructor at instance init time. You can dig out nr-object.cpp and nr-object.h from source control and investigate. However, using it would require you to rewrite the init functions of all SPObjects.
Some additional details: NRObject had a virtual function in its class, called invoke_ctor, which was replaced in every derived object by something similar to you GMEMWRAP trick - a static function that was a member of template which simply called the constructor. The dispose function was handled in a similar way.
Replacing GObject-style initialization with constructor / destructor shims in the style of NRObject would considerably simplify removing the GObject dependency later and reduce the burden of maintaining the init / dispose functions.
Regards, Krzysztof
On 07/31/2013 05:51 PM, Krzysztof Kosiński wrote:
2013/7/30 Sebastian Götte <jaseg@...2974...>:
Hi, I'm currently having some problems allocating GObjects. I just added a class called SPPoint [0]. When I try to instantiate an object of that type (whether through SPObject/sp_object_child_added or manually from GDB using g_object_new does not matter), g_object_new returns an GObject* that contains a zero class: {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0} (this is not good as it breaks everything else about G_OBJECT). I was able to track down the problem to g_type_create_instance returning that when passed the new SPPoint type:
I think this is the problem:
static void sp_point_init(SPPoint *point){ new (point) SPPoint(); }
This will destroy parent initialization. Parent init functions which run before this one invoke the member constructors manually. In existing code, the constructor of SPObject is never called. The destructors are called manually in the dispose function. Instead of calling new, you have to construct each member separately.
Ah, I see. well, then it appears I can't use a C++ constructor here (I tried to avoid initializing all members to zero manually). Thanks.
participants (5)
-
Johan Engelen
-
Jon Cruz
-
Krzysztof Kosiński
-
Sebastian Götte
-
Tavmjong Bah