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 495762 - need get_pointer for RefPtr<>
need get_pointer for RefPtr<>
Status: RESOLVED FIXED
Product: glibmm
Classification: Bindings
Component: general
2.14.x
Other All
: Normal normal
: ---
Assigned To: gtkmm-forge
gtkmm-forge
: 595793 (view as bug list)
Depends on: 755037
Blocks:
 
 
Reported: 2007-11-11 01:30 UTC by Hubert Figuiere (:hub)
Modified: 2018-03-21 09:19 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Hubert Figuiere (:hub) 2007-11-11 01:30:16 UTC
get_pointer is need for boost::bind to work with RefPtr<>

Here is the code:

namespace Glib {

	/** Dereference Glib::RefPtr<> for use in boost::bind */
	template< class T_CppObject >
	T_CppObject *get_pointer(const Glib::RefPtr< T_CppObject >& p)
	{
		return p.operator->();
	}

}


With that I can pass a Glib::RefPtr<> to a boost::bind
Comment 1 Murray Cumming 2007-11-12 07:36:34 UTC
I will investigate. I am surprised that boost::bind even knows that RefPtr is a smartpointer. I would expect it to deal with it like any other class that has a copy constructor and operator=.
Comment 2 Hubert Figuiere (:hub) 2007-11-12 16:43:19 UTC
When binding a member function, boost::bind accept pointers or something that return pointer of the same type using a get_pointer() free function. It does not accept plain-objects as the object instance to call a member function.
Comment 3 Murray Cumming 2007-11-30 11:07:24 UTC
Somewhere or other you showed me some example code of how this might be used, but I can't find that now. Could you please show us a code snippet here?
Comment 4 Hubert Figuiere (:hub) 2007-11-30 14:49:22 UTC
This is not the easiest example

// icon_theme is a Glib::RefPtr<Gtk::IconTheme>
std::vector<int> icon_sizes(icon_theme->get_icon_sizes(name));

std::list< RefPtr <Gdk::Pixbuf> > icons;

std::for_each(icon_sizes.begin(), icon_sizes.end(),
              // store the icon
              boost::bind(&std::list< RefPtr<Gdk::Pixbuf> >::push_back, 
                          boost::ref(icons),
                          // load the icon
                          boost::bind( &IconTheme::load_icon,
                                       boost::ref(icon_theme),
                                       boost::ref(name), _1,                           Gtk::ICON_LOOKUP_USE_BUILTIN)));


You need get_pointer() for icon_theme to call IconTheme::load_icon() in the second binder.
Comment 5 Murray Cumming 2008-01-20 18:03:55 UTC
I am still very nervous about adding this to the API because it would almost certainly be used by accident. But I guess I might commit it if you submit an actual patch. And it would be nice to have something in tests/, though the test would not be able to build as part of the main build system, because we don't want to depend on boost. Sorry for not being certain.
Comment 6 Hubert Figuiere (:hub) 2008-01-20 18:10:23 UTC
using by accident? I don't see what the problem is, given that:

1/ it is possible de get the pointer anyway
2/ it is meant to mimic se semantics of boost, which is part of the TR1 for the libstc++.

I'll see about providing a patch. 
Comment 7 Murray Cumming 2008-01-20 18:24:30 UTC
> 1/ it is possible de get the pointer anyway

It's difficult, requiring use of operator->(). It would be impossible if I could achieve that.
Comment 8 Hubert Figuiere (:hub) 2008-01-20 19:51:29 UTC
I don't agree with the necessity of preventing that. Actually I believe that it should be allowed.
Comment 9 Jonathon Jongsma 2008-02-21 03:40:27 UTC
Here's another example where it might be useful to access the underlying pointer -- creating a slot from a member function of an object within a refptr:

Glib::RefPtr<Foo> foo;
button.signal_clicked ().connect (sigc::mem_fun (foo.operator->(), &Foo::bar));
Comment 10 Murray Cumming 2008-02-21 10:01:24 UTC
That's fairly unusual (though not totally unlikely). You'd usually connect the signal in a member method, where you'd have access to "this". 
Comment 11 Jonathon Jongsma 2008-02-21 13:35:53 UTC
Yes, I agree it's quite unusual, but I just had a situation where I wanted to do it.
Comment 12 Hubert Figuiere (:hub) 2008-02-21 14:17:37 UTC
for this, I'd rather see sigc accepting smart pointers, like boost::bind does. (and that what this bug is about, implement the mechanism to allow boost::bind to accepte the smart pointer. This is safer as the binder actually keep a copy of it.
Comment 13 Jonathon Jongsma 2008-02-21 14:22:16 UTC
I agree that would be a better solution if it could be achieved in sigc++
Comment 14 Milosz Derezynski 2008-07-29 17:56:55 UTC
Sorry to just chime in. Here is an example like Hubert's  earlier just less abstract and actually useful:

MiscWidgets.FilterEntry->signal_changed().connect (sigc::mem_fun (CastData.FilterStore.operator->(), &TreeModelFilter::refilter));

FilterStore is a (like you can see) TreeModelFilter and FilterEntry is a Gtk::Entry.

Ultimately i think it would be good if sigc new about Glib's RefPtr<> directly but that's obviously not possible.

Thanks for consideration,
Milosz
Comment 15 Milosz Derezynski 2008-07-29 17:59:10 UTC
Sorry i meant less abstract than Jonner's example.
Comment 16 Murray Cumming 2008-08-04 11:02:27 UTC
Yes, that's the only real example that I've found. However it is quite unusual (though real), because you must of course:
- connect a signal to something other than this.
- connect a signal to a derived class, to even add that signal handler.

I still feel it's not worth adding the risk and confusion, but I'm slightly persuaded. 
Comment 17 Alexander Shaduri 2008-08-16 15:50:04 UTC
Another example (maybe there's another way, I don't know):

Glib::RefPtr<Gtk::Builder> b = Gtk::Builder::create_from_file("file.ui");
Glib::RefPtr<Glib::Object> o = b->get_object("some_action");  // it's Gtk::Action, so get_widget() won't work

dynamic_cast<Gtk::Action*>(o->operator->())->signal_activate().connect(someslot);

If there's another way to connect slots to Gtk::Action objects from Gtk::Builder, I certainly would like to know.
Thanks.
Comment 18 Hubert Figuiere (:hub) 2008-08-16 16:25:17 UTC
(In reply to comment #17)
> Another example (maybe there's another way, I don't know):
> 

No. This is totally unrelated. get_pointer() is not meant to do hackish casting and the exemple you give is actually an argument against.
Comment 19 Alexander Shaduri 2008-08-16 20:58:44 UTC
Now that I think about it, yes, it may be done using RefPtr's cast_dynamic. However, I still think there are situations where get_pointer() would be nice. I mean, you can certainly work around it (without operator->()), but there are situations where you just don't want to do that - for interoperability, consistency of API, etc...
Plus, some custom casts can't be applied (down_cast that works with both polymorphic and non-polymorphic objects, etc...).
Anyway, operator->() works fine, so no real need to me.
Comment 20 Daniel Elstner 2009-05-21 00:39:25 UTC
(In reply to comment #10)
> That's fairly unusual (though not totally unlikely). You'd usually connect the
> signal in a member method, where you'd have access to "this". 

Usual, but by no means mandatory.  Nor is it good style to introduce yet another indirection if none is necessary.  Case in point:

http://github.com/danielkitta/kcio/blob/6b0b5c49c2e9bca56b63d23efc2c2f0551c98b81/kc-keyboard/inputwindow.cc#L186

This is not something I just put in there specifically for this bug comment; see the date of the commit.

1) There is nothing wrong or even unusual about creating a slot to a method of another object.  In fact, it is good style to avoid depending on state when you don't have to.  In my experience, this sort of cross-object connection is actually quite common, and very often it turns out that the only reason to go through *this is just some stupid housekeeping need.

2) It is a bit odd that we go to great lengths to use STL containers wherever feasible, but then prevent the generic STL algorithms from being used on a vector of RefPtr<> elements. Heck, the algorithms are actually the important part -- they are the reason to provide STL-style interfaces to your own container types!

3) The feared misuse of operator*() is in reality a non-issue.  Consider:

    void do_foo(Object& obj);
    // ...
    Glib::RefPtr<Object> bar = something();
    do_foo(*bar);

If this is so bad; indeed bad enough to make us reduce the usability of our API to prevent people from doing it, then what about this?

    void do_foo(std::string& str);
    // ...
    std::string bar = "something";
    do_foo(bar);

Isn't this in fact even worse, given that you don't even need to put a "*" in there?

Now, the horror of horrors:

    Glib::RefPtr<Object> something();
    // ...
    Object& bar = *something();

Evil?  Could be.  But very often, it's actually not a problem at all.  It is about as evil as

    Widget* widget = bin->get_child();
.
Which is to say, it is slightly evil but pretty benign in the grand scheme of things.  Also, in those cases where it actually is an error, the failure mode will be of the tame kind.  Even if it doesn't crash right away, Valgrind will easily detect the invalid memory access.

When it comes to messing up RefPtr<>, I'd be far more worried about unmatched ref and unref calls.  Dereferencing a RefPtr<> won't cause this sort of problem.  In fact, even putting it back into another RefPtr<> is not a problem since the reference count is a member of the object itself.  Seriously, exposing reference() and unreference() as public API is much more dangerous and nasty than RefPtr<>::operator*() could possibly be.

On a side note; we really should have a RefPtr<> ctor that takes a reference in gtkmm 3.
Comment 21 Murray Cumming 2010-03-26 09:55:56 UTC
*** Bug 595793 has been marked as a duplicate of this bug. ***
Comment 22 Michael Edwards 2011-01-02 22:24:24 UTC
I recently encountered another legitimate usage pattern that currently requires explicit calls to p.operator->() (with p a Glib::RefPtr<whatever>).  For my purposes, the syntactic ugliness of p.operator->() is not a big deal; it's easily hidden inside other test/mock scaffolding.  But I'd like to see Glib::RefPtr acquire the get() method and get_pointer() free function, to reduce the impedance mismatch between Glibmm and frameworks like Google Mock that provide glue templates compatible with other smart pointers like std::tr1::shared_ptr (std::shared_ptr in C++0x).

I'm writing unit test coverage, using Google Test and Google Mock, for code that uses Glibmm.  The unit tests exercise classes which hold RefPtrs to instances of classes from the Glib and Gio namespaces.  In order to verify the sequence of calls to these objects' methods, I make use of the "delegating calls to a real object" pattern described at http://code.google.com/p/googlemock/wiki/CookBook#Delegating_Calls_to_a_Real_Object .

This technique uses a Google Mock template function called Invoke, which (like boost::bind and STL algorithms) wants a pointer to a class instance and a pointer to an instance method on that class.  This particular function won't accept a smart pointer instead, but there are other Google Mock mechanisms (like Pointee) that will; they rely on the existence of an instance method called get() which retrieves the raw pointer.  This is compatible with std::tr1::shared_ptr (whose get() method is the same as operator->() except that it doesn't explode when the stored pointer is null).  It is also documented to work with other comparable smart pointers like linked_ptr and scoped_ptr.

In general, many template techniques rely on the ability to craft an expression with a specific type and then to extract compile-time properties (like signatures of instance methods) from it.  I think the designers of the TR1 shared_ptr included the get() method (and the get_pointer() free function) largely for uses like this, not because there are many scenarios in which it's a good idea for "normal" code to pull out the raw pointer and *do* anything with it.
Comment 23 alex 2012-06-09 21:08:09 UTC
Please document at least the trick with Glib::RefPtr<xy>.operator->(). It would save much time.
Comment 24 Murray Cumming 2016-04-10 11:26:14 UTC
I'm making this bug dependent on bug #755037 , because when we use std::shared_ptr instead of RefPtr, we'll have std::shared_ptr<>::get().

As we've decided to use std::shared_ptr<> as soon as the ABI allows, I guess we should go ahead and add RefPtr::get() as a kind of preparation for that. I yield.
Comment 25 Daniel Boles 2017-08-13 12:15:55 UTC
master has shared_ptr now, so what are the chances of this happening in 2.4? (i.e. 2.52 at present)
Comment 26 Kjell Ahlstedt 2018-03-21 09:19:15 UTC
I've added Glib::RefPtr::get(), analogous to std::shared_ptr::get(), in the
glibmm-2-56 branch. That's a partial fix of this bug.

The get_pointer() function does not exist in C++11 or C++14. As far as I can see
there's no std::get_pointer(const std::shared_ptr&). Therefore I prefer not to
add a Glib::get_pointer(const Glib::RefPtr&) function.

Closing this bug. Feel free to reopen it, if you insist that a get_pointer()
function shall be added to glibmm.