[cairo] Re: cairo c++ bindings

Marco Manfredini mldb at gmx.net
Fri Dec 2 03:19:58 PST 2005


On Monday 28 November 2005 21:53, Bill Spitzak wrote:
> Murray Cumming wrote:
> > An if(somebool) will not add a significatn amount of run-time overhead.
> > I'd be happy to add a Cairo::set_ignore_errors(bool) function.
> Actually it will if the code is inlined, as it can add significant size
> to the code and thus make things not fit in caches. A quick test reveals
> that this triples the size of the inlined code (for a phony test with
> one argument passed to the other function).

This is exactly what I've observed when writing wrappers, and there is another 
point that hasn't been discussed with the idea of "policies": How do I assign 
precise throw() specifications to the members? Being able to assert what a 
function throws makes a good argument to code review and literally pays out 
when the compiler sees that it can remove clean up frames from the code. 

> My preference would be for the C++ wrapper to not test anything or throw
> any exceptions, and to just wrap the "test status" call like every other
> Cairo interface. Calling code can do "if (cairo_c->error()) throw
> exception;"
>
> The ideas mentioned below for using templates to make a different class
> that does throw exceptions may be a good idea, though, as long as the
> header files are still readable.

I don't event think that there is a need to deal with exceptions at all 
(except for the requirement that the wrappers are exception safe), because an 
user defined exception policy can easily be defined externally using a proxy 
class: 

void drawSomething(Context _c)  // Context does not care for status
{
	guarded<Context> c(_c); 
	c->moveTo(0,0); 
	c->lineTo(10,10); // every call is status checked and throws if neccesary.
	...
}

To illustrate this, here's a rought sketch of guarded: 

// this needs some polishing to handle const and reference parameters: 
template<class T>
struct guarded
{
	private:
	struct proxy
	{
		T &t; 
		inline proxy(T &_t) throw() : t(_t) {}
		inline T * operator -> () throw() { return & t; }
		inline ~proxy() throw(Status) 
		{
			Status s=t.status();
			if (s != STATUS_SUCCESS) 
			{
				throw s; 
			}
		}
	}; 
	T object; 
	public:
	inline guarded(T obj) throw() : object(obj) {}
	// operator -> cascading
	inline proxy operator -> () throw() { return object; }
	inline operator T & () const throw() { return object; }
};

This looks like overhead, but the essentially the optimizer will remove the 
creation of the proxy alltogether and just leave the check from ~proxy.

Marco


More information about the cairo mailing list