tp_list_connection_managers() takes a TpConnectionManagerListCb callback that provides a list of const TpConnectionManager*.
But const should never be used in C for complex types. It is only useful for simple types (such as char) or structs of simple types, such as GdkRectangle. Unlike C++, C lacks the mutable keyword, and lacks const and non-const method overloads, so const just gets annoying for complex types. This is the approach used by GTK+.
For instance, this code causes compiler warnings because we use g_object_get() on a const instance. To avoid these, const must be annoyingly casted away almost always.
on_list_connection_managers(TpConnectionManager * const *connection_managers,
const GError *error,
TpConnectionManager * const *cm_iter = connection_managers;
for (; *cm_iter != NULL; ++cm_iter)
const TpConnectionManager *cm = *cm_iter;
gchar *cm_name = NULL;
about the general horribleness of the pointers-to-pointers in the API.)
Er, isn't this basically the same code as examples/client/list-managers.c? Except that the example handles errors correctly, while the code you pasted appears to dereference @cms even if @error is non-NULL, causing a segfault (@cms is documented as "... or %NULL on error".
list-managers.c doesn't bother declaring an equivalent of your variable "cm" (it just uses *iter directly, since there's only one mention of it in the rest of the function) but the following patch to make it resemble your code compiles without warnings too. The problem is that you used "const TpConnectionManager *" where just "TpConnectionManager *" would do.
TpConnectionManager * const * is a const pointer (pointer that you must not free) to TpConnectionManager *, so it is correct to dereference it and assign the result to a TpConnectionManager * variable.
diff --git a/examples/client/list-managers.c b/examples/client/list-managers.c
index 33e8aee..904e8b0 100644
@@ -39,9 +39,10 @@ got_connection_managers (TpConnectionManager * const *cms,
for (iter = cms; *iter != NULL; iter++)
+ TpConnectionManager *cm = *iter;
- g_object_get (*iter,
+ g_object_get (cm,
(In reply to comment #1)
> Er, isn't this basically the same code as examples/client/list-managers.c?
> Except that the example handles errors correctly, while the code you pasted
> appears to dereference @cms even if @error is non-NULL, causing a segfault
> (@cms is documented as "... or %NULL on error".
I left the error checking out on purpose to demonstrate more clearly the problem with const. Of course.
> list-managers.c doesn't bother declaring an equivalent of your variable "cm"
> (it just uses *iter directly, since there's only one mention of it in the rest
> of the function) but the following patch to make it resemble your code compiles
> without warnings too. The problem is that you used "const TpConnectionManager
> *" where just "TpConnectionManager *" would do.
> TpConnectionManager * const * is a const pointer (pointer that you must not
> free) to TpConnectionManager *,
I thought that would be
TpConnectionManager * * const
because you can generally read pointer syntax backwards, but as I've said elsewhere pointer to pointer syntax is horrible and should be avoided. At the least, typedefs should be used to clarify it.
I tried it and you seem to be right. Sorry. Thanks.
pointer to pointer can be hidden with a typedef, just like GStrv for gchar**. This is useful for bindings too. For example a binding can generate a list of strings if it sees GStrv, but can't do anything if it is a GList* or a gchar**.
What about that?
typedef TpConnectionManagerArray TpConnectionManager* const*;
Why not declare the parameter as
TpConnectionManager * connection_managers 
That's equivalent and removes all confusion.
Xavier, that doesn't add much (even when we correct your syntax).
I was thinking more of
typedef TpConnectionManager* TpConnectionManagerPtr;
const TpConnectionManagerPtr* connection_managers;
It's not pretty, but pointer-to-pointer never is (a GList would be better), but it is at least more readable.