glib dependency for the X Server

Carsten Haitzler (The Rasterman) raster at rasterman.com
Thu Apr 6 20:01:20 PDT 2006


On Fri, 07 Apr 2006 04:35:39 +0200 Bernardo Innocenti <bernie at develer.com>
babbled:

> Carsten Haitzler (The Rasterman) wrote:
> 
> > yeah- BUT for me - i tend to DESIGN my code where "0" is a plausible and
> > DESIREABLE "default starting" value OR an invalid value (eg a NULL pointer -
> > see above - i know about its caveats that it may NOT be 0)  so i wont
> > de-reference a pointer if its null (ie the object hasn't been attached yet
> > for example or its in a "created but not initialised state -
> 
> Such intermediate initialization states are a no-no since the RAII
> concept was invented.  Forgetting to initialize stuff is one of the
> most common sources of problems that are difficult to reproduce and
> debug.
> 
> Sane C++ libraries (this would rule out MFC and its two-stage construction)
> use constructors to make sure objects are either fully usable or don't
> exist at all.

but frankly that's a performance dog. it sucks. badly. example:

i create an image object. the image object contains the info:
width, height, colorspace (RGB or RGBA), pixel data

now - this image object is perfectly usable a lot of the time with NO PIXEL
DATA. i simply need to know its dimensions. so i can load just the header of
the file - and not decode a single pixel, allowing me to perform an ultra-fast
loads and queries and only decode pixel data on-demand (ie the first time the
pixels are actually needed for rendering or inspection). when the object has
all the meta-info but no pixels - it's in a "partly initialized" state. it
finishes its init when the first time pixels are needed. until then i KNOW the
the pixel pointer is NULL and that means "still need to fetch those". my code
would crawl a lot more slowly if i didn't do this. i can setup a massive array
of image objects (imagine a photo gallery) in a scrolled view - and just
blindly create, query dimensions and lay out based on that. the data is decoded
on-demand, deferring the work and saving ram for things you don't see.

> C programs can be designed to do the same by providing constructor
> functions that do both the allocation and the initialization of
> objects with a single call:
> 
>   foobar *fb = foobar_new();
>   ...use fb...
>   foobar_delete(fb);
> 
> This suggestion may seem very trivial, but there are far too
> many APIs around that don't follow this simple pattern.

all my api's follow this. the problem is IN the foobar_new(). if i calloc() the
foobar struct - then i don't need to remember to set 80 or 100 struct members to
"sane states" - they are all already 0. i also GIVE the libc implementation the
chance to be optimal and if it's a fresh page - don't zero it out. if not - i
would be memset()ing it anyway - and now libc knows less and is not able to
make such an optimization - regardless if it does or not, i have removed the
ABILITY for it to do so (or well made it a lot trickier).

> When static allocation is also needed, a second function
> could do just the initialization step on an existing buffer:
> 
>   foobar fb;
>   foobar_ctor(&fb);
>   ...use fb...
>   foobar_dtor(&fb);
> 
> In C, one would still have to be careful about destroying all
> objects manually, but that's very difficult to do without C++.
> 
> 
> > eg an image object
> > would have a struct for its control info and properties but may not alloc
> > the pixel data until needed - i.e. i may load an image file header and get
> > its width, height, colorspace info etc., but not decode pixel data until
> > demanded, saving a fair bit of work when you just want to create objects
> > that don't become visible until later - or never)
> 
> There is a GoF pattern for safe lazy initialzation, but I can't
> remember if it's called Proxy, Flyweight or something else.
> 
> Basically, the object acts as if it was fully initialized, but
> the slow part of the initialization only happens the first time
> a method needs to access the data.

yup - thats exactly what i do in many places. it pays off very handsomely. but
i KNOW the pixel pointer is a known sane state and i can check for it and then
fill it in when needed. if i forget to set it up at the start and now its some
strange value - how do i know its valid or not? i need to add another flags
field for that then - another point of failure if i forget to set that up
too... some of my structs have more than 100 members. i would become homicidal
if i was manually setting everyone to some value on alloc.

> The basic idea for robust APIs is to try as much as possible
> to shield client code from implementation details such as these.

i do :) i do the callocs within the api - foobar_new() calls calloc when
allocating the object and returning it.

> -- 
>   // Bernardo Innocenti - Develer S.r.l., R&D dept.
> \X/  http://www.develer.com/
> 


-- 
------------- Codito, ergo sum - "I code, therefore I am" --------------
The Rasterman (Carsten Haitzler)    raster at rasterman.com
裸好多
Tokyo, Japan (東京 日本)



More information about the xorg mailing list