After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 547901 - Implementing unwrapped copy functions for Glib::NodeTree
Implementing unwrapped copy functions for Glib::NodeTree
Status: RESOLVED FIXED
Product: glibmm
Classification: Bindings
Component: build
2.17.x
Other Linux
: Normal normal
: ---
Assigned To: gtkmm-forge
gtkmm-forge
Depends on:
Blocks: 547889
 
 
Reported: 2008-08-15 11:56 UTC by Szilárd Pfeiffer
Modified: 2008-09-03 15:42 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
possible solution of problems mentioned in comment 0 (1.90 KB, patch)
2008-08-15 12:04 UTC, Szilárd Pfeiffer
none Details | Review
modified patch which considers the questions in comment 2 (3.17 KB, patch)
2008-08-22 15:08 UTC, Szilárd Pfeiffer
none Details | Review
modified patch related to comment 5 (4.07 KB, patch)
2008-08-26 06:03 UTC, Szilárd Pfeiffer
none Details | Review
patch which reflects to comment 10 (6.67 KB, patch)
2008-09-01 19:54 UTC, Szilárd Pfeiffer
none Details | Review

Description Szilárd Pfeiffer 2008-08-15 11:56:58 UTC
1; there are some unwrapped functions (g_node_copy, g_node_copy_deep)
2; copy constructor is not implemented and the default may cause problems
3; destructor leaks the C++ wrapper objects of children
4; unlink member function has wrong parametering
Comment 1 Szilárd Pfeiffer 2008-08-15 12:04:03 UTC
Created attachment 116660 [details] [review]
possible solution of problems mentioned in comment 0

ChangeLog:

2008-08-15  Szilárd Pfeiffer  <szilard.pfeiffer@gmail.com>

    * glib/src/nodetree.hg: Implemented copy contructor. Wrapped function
    g_node_copy and g_node_copy_deep. Fixed memory leak in case of the 
    destructor. Fixed parametering problem of member function unlink().
    Bug #547901
Comment 2 Murray Cumming 2008-08-18 08:36:45 UTC
There are maybe some comments missing in the code to explain obvious questions such as:

a) Why doesn't copy_deep() just use g_node_copy_deep()?
b) Why do we need copy_deep() if we have a copy constructor that does the same thing? Or doesn't that do a deep copy? I think it should.
c) Why would we want the copy() function that shares the underlying data pointers? Isn't that just an invitation to memory problems?

The new destructor implementation should also have a comment saying why it doesn't just use g_node_destroy(). 
Comment 3 Szilárd Pfeiffer 2008-08-22 15:08:27 UTC
Created attachment 117227 [details] [review]
modified patch which considers the questions in comment 2

a) copy_deep must construct the C++ wrapper, g_node_copy_deep cannot do that
b) constructors copies the data now (originally I want to avoid that, but it would cause much more serious problems)
c) copy not wrapped (it cannot be, because constructors always copy the data)
d) destructor implementation is commented

If the patch looks good and you merge it, please consider removing the comment of the related test case.
Comment 4 Murray Cumming 2008-08-22 15:19:51 UTC
Thanks, but:

(In reply to comment #3)
> Created an attachment (id=117227) [edit]
> modified patch which considers the questions in comment 2
> 
> a) copy_deep must construct the C++ wrapper, g_node_copy_deep cannot do that

I don't see a comment in the constructor about g_node_copy_deep(). 

I also don't understand why you have added a copy_deep() method. Why shouldn't people just use the copy constructor.

Also, if there is a copy constructor, surely there should be an operator=()?, with them both maybe sharing some code.

> b) constructors copies the data now (originally I want to avoid that, but it
> would cause much more serious problems)

That sounds safer. Thanks.

> c) copy not wrapped (it cannot be, because constructors always copy the data)
> d) destructor implementation is commented
> 
> If the patch looks good and you merge it, please consider removing the comment
> of the related test case.

Feel free to change the test case in your patch.


Comment 5 Szilárd Pfeiffer 2008-08-26 06:01:55 UTC
(In reply to comment #4)
> Thanks, but:
> 
> (In reply to comment #3)
> > Created an attachment (id=117227) [edit]
> > modified patch which considers the questions in comment 2
> > 
> > a) copy_deep must construct the C++ wrapper, g_node_copy_deep cannot do that
> 
> I don't see a comment in the constructor about g_node_copy_deep().
I put the comment inside the copy_deep() function.
 
> 
> I also don't understand why you have added a copy_deep() method. Why shouldn't
> people just use the copy constructor.
They can use both of them. If somebody like the C-like  version he can use copy_deep(), if he likes the C++ version he can use the copy constructor.

> 
> Also, if there is a copy constructor, surely there should be an operator=()?,
> with them both maybe sharing some code.
> 
Which operator= is on your mind?

 - operator=(const T& data)
   it is not a big deal, but the functionality can be acquired by data() function
 - operator=(const NodeTree<T>& node)
  What should it mean? Should it change parent/children/next/prev pointers, or only overwites the data with the copy of node.data()? In my humble opinion it might be the source of misunderstandings.
Comment 6 Szilárd Pfeiffer 2008-08-26 06:03:59 UTC
Created attachment 117378 [details] [review]
modified patch related to comment 5
Comment 7 Murray Cumming 2008-08-26 13:42:43 UTC
Thanks. I have committed that. However:

> > I also don't understand why you have added a copy_deep() method. Why shouldn't
> > people just use the copy constructor.
> They can use both of them. If somebody like the C-like  version he can use
> copy_deep(), if he likes the C++ version he can use the copy constructor.

That doesn't seem sensible. It's a C++ API. Having two ways to do it just clutters the API and gives the impression that one way does something different. I removed copy_deep().

> > Also, if there is a copy constructor, surely there should be an operator=()?,
> > with them both maybe sharing some code.
> > 
> Which operator= is on your mind?
> 
>  - operator=(const T& data)
>    it is not a big deal, but the functionality can be acquired by data()
> function
>  - operator=(const NodeTree<T>& node)

This one.

>   What should it mean? Should it change parent/children/next/prev pointers, or
> only overwites the data with the copy of node.data()? In my humble opinion it
> might be the source of misunderstandings.

In general, I think that any copy constructor (not all constructors) should have a corresponding operator=() because it's not always easy to know when one or the other will be used, so they should both exist, and should both do the same thing. I have added that.

I think that's everything, but please reopen if necessary.

Thanks for your work and attention on this.

Comment 8 Szilárd Pfeiffer 2008-08-27 09:24:47 UTC
(In reply to comment #7)
> 
> In general, I think that any copy constructor (not all constructors) should
> have a corresponding operator=() because it's not always easy to know when one
> or the other will be used, so they should both exist, and should both do the
> same thing. I have added that.

In general, I really agree with you, but it is a little bit special case.

In this case there is a difference between the copy constructor and the operator= in my mind. The copy constructor creates a brand new NodeTree object which is a root item, so it has neither parent nor any siblings.

In case of operator= the object in question may be in a tree, so it may have parent and siblings. If we want to retain the original position of the object in the tree we must not unlink it (as it happens in your implementation).

The another problem with the implementation of the operator= is the fact that it does not copy the data as the copy constructor does.
Comment 9 Murray Cumming 2008-08-27 10:43:06 UTC
(In reply to comment #8)
> In this case there is a difference between the copy constructor and the
> operator= in my mind. The copy constructor creates a brand new NodeTree object
> which is a root item, so it has neither parent nor any siblings.
> 
> In case of operator= the object in question may be in a tree, so it may have
> parent and siblings. If we want to retain the original position of the object
> in the tree we must not unlink it (as it happens in your implementation).

That's weird. I guess we need to not affect the other tree, while creating a new one.

> The another problem with the implementation of the operator= is the fact that
> it does not copy the data as the copy constructor does.

Oops.

Could you patch it to do that?

Comment 10 Szilárd Pfeiffer 2008-08-27 11:46:27 UTC
(In reply to comment #9)
> (In reply to comment #8)
> > In this case there is a difference between the copy constructor and the
> > operator= in my mind. The copy constructor creates a brand new NodeTree object
> > which is a root item, so it has neither parent nor any siblings.
> > 
> > In case of operator= the object in question may be in a tree, so it may have
> > parent and siblings. If we want to retain the original position of the object
> > in the tree we must not unlink it (as it happens in your implementation).
> 
> That's weird. I guess we need to not affect the other tree, while creating a
> new one.

I do not understand what kind of "other tree" you have mentioned. The problem is that the clear function what you have created from the destructor unlinks the node (if it is not the root) which the operator= function belongs to.

> 
> > The another problem with the implementation of the operator= is the fact that
> > it does not copy the data as the copy constructor does.
> 
> Oops.
> 
> Could you patch it to do that?
> 
Yes, I could.
Comment 11 Murray Cumming 2008-08-27 12:56:35 UTC
> > > In case of operator= the object in question may be in a tree, so it may have
> > > parent and siblings. If we want to retain the original position of the object
> > > in the tree we must not unlink it (as it happens in your implementation).
> > 
> > That's weird. I guess we need to not affect the other tree, while creating a
> > new one.
> 
> I do not understand what kind of "other tree" you have mentioned. The problem
> is that the clear function what you have created from the destructor unlinks
> the node (if it is not the root) which the operator= function belongs to.

Yes, so we should not do that.

For instance, after:

1: node_tree other = get_some_node_tree_from_somewhere()
2: node_tree child = other->get_some_child_node();
3: child = get_some_diferent_node();

other should be the same after step 3 as at step 1.
Comment 12 Szilárd Pfeiffer 2008-09-01 19:54:39 UTC
Created attachment 117799 [details] [review]
patch which reflects to comment 10

ChangeLog:

2008-08-26  Szilárd Pfeiffer  <szilard.pfeiffer@gmail.com>

        * glib/src/nodetree.hg: Implemented clone function to merge the 
        constructors into that and fixed clear function the operator= 
        function.
        * tests/glibmm_nodetree/main.cc: Simplified the test case.
        Bug #547901.
Comment 13 Murray Cumming 2008-09-03 15:42:25 UTC
Committed. Thanks for being so responsive and thanks for making this class solid.