PDA

View Full Version : Constructing ClanLib 0.9 Objects



rombust
12-18-2008, 04:42 PM
While copying objects in ClanLib 0.9, we can use the following method:


CL_GraphicContext gc = display_window.get_gc();
CL_Font old_font = gc.get_font();

This has virtually no overhead, as all it does internally is copy the implementation pointer (ie the implementation itself is not copied)

This is useful. We can construct objects using the following method:


CL_Font my_font
my_font = CL_Font(gc, "Tahoma", 12);

...But...

We cannot do:


CL_PushButton button;
button = CL_PushButton(&gui_window);

As an appropriate constructor does not exist.

Is this intentional?

Any thoughts?

Note:
We have to be careful using the first method, as we can fall into the following trap:

void myfunction(const CL_DisplayWindowDescription &desc)
{
CL_DisplayWindowDescription copy_desc = desc;
copy_desc.set_width(100);
}
This would also change "desc". The compiler would not warn that we are modifying a const. (See http://en.wikipedia.org/wiki/Const_correctness#Loopholes_to_const-correctness )

This is why copy() was added to CL_FontDescription API

Magnus Norddahl
12-21-2008, 08:27 AM
Yes, this is the classic 'sharedptr' problem in the ClanLib API.

Sometimes I really wish I had never used shared pointers in the API, since they have so many subtle side effects:


the const qualifier being lost
object creation order not always matching destruction order
extra coding time with the Impl objects
object sharing when not desirable (the copy() func)


The GUI framework in ClanLib deliberately uses traditional class inheritance (with the intention that apps do the inheritance), which is why the CL_PushButton example of yours doesn't work. But the ClanLib classes in that framework still use the sharedptr stuff for data hiding.

Other exceptions: CL_Rect, CL_Point, CL_Size, CL_Vec, CL_Mat and the string classes.

The way I see it, the problem is that we made too many objects act like 'handle objects'. Certain types of objects are better dealt with as 'normal C++' objects. By that I mean that they need to copy themselves on assignment. In particular the objects that really need this are our description classes and our state classes.

I think the technically correct way of fixing the 'const correctness' problem is to change the sharedptr from a member to something like:



class CL_DisplayWindowInterface
{
public:
void flip();
};
typedef CL_SharedPtr<CL_DisplayWindowInterface> CL_DisplayWindow;
CL_DisplayWindow cl_create_window();


The problem with this approach is that it really messes up the API. Not only are objects not created with constructors, the functions aren't accessed with a dot (.), but instead with the -> operator. I'm not sure it is worth it simply to obtain const correctness.