[Rcpp-devel] idiom for creating an informative message for an exception

romain at r-enthusiasts.com romain at r-enthusiasts.com
Fri Dec 10 21:01:40 CET 2010





Le 10 déc. 2010 à 08:33 PM, Douglas Bates <bates at stat.wisc.edu> a écrit :

> On Sat, Dec 4, 2010 at 8:13 AM, Romain Francois
> <romain at r-enthusiasts.com> wrote:
>> Le 02/12/10 22:15, Douglas Bates a écrit :
>>> 
>>> In the lme4a package I mixed calls to Rf_error and throwing C++
>>> exceptions.  This is causing problems and I plan to replace the calls
>>> to Rf_error by exceptions so that there is a consistent approach.
>>> 
>>> Many of the calls to Rf_error take advantage of the fact the Rf_error
>>> implicitly calls sprintf to create the error message.  Thus I have
>>> calls like
>>> 
>>>        if (!d_x.size() == d_nrow * d_ncol)
>>>            ::Rf_error("%s: Dim = (%d, %d) is inconsistent with x.size() =
>>> %d",
>>>                       "ddenseMatrix::ddenseMatrix", d_nrow, d_ncol,
>>> d_x.size());
>>> 
>>> Is there a similar idiom for creating an exception's "what" argument?
>>> I imagine I could add std::strings and maybe use some iostreams or
>>> something like that ...
>> 
>> Hello,
>> 
>> I've added the sprintf template, defined as:
> 
> I think there is an off-by-one problem in this template.  The maximum
> index in buffer is MAX_SIZE - 1, not MAX_SIZE.  I suggest declaring
> buffer to be MAX_SIZE + 1

Oops. 
Go ahead.


>> template <int MAX_SIZE>
>> const char* sprintf( const char *format, ...) {
>>    static char buffer[MAX_SIZE];
>>    va_list(ap);
>>    va_start(ap, format);
>>    vsprintf( buffer, format, ap);
>>    va_end(ap);
>>    buffer[MAX_SIZE] = '\0';
>>    return strdup( buffer ) ;
>> }
>> 
>> so that we can do things like :
>> 
>> fx <- cxxfunction( , '
>>    return CharacterVector::create(
>>        sprintf<100>( "bla %d", 10 ),
>>        sprintf<100>( "bla %s %d", " bla" , 10)
>>        );
>>    ', plugin = "Rcpp", verbose = TRUE
>> )
>> fx()
>> 
>> 
>> This way, I think you can create your exception class like this:
>> 
>> 
>> fy <- cxxfunction( , '
>>    throw foo_exception( 10, 10, 10 ) ;
>>    ', includes = '
>> 
>>    class foo_exception : public std::exception {
>>        public:
>>            foo_exception( int nrow_, int ncol_, int size_):
>>                nrow(nrow_), ncol(ncol_), size(size_){}
>>            inline const char* what() const throw(){
>>                return sprintf<100>(
>>                    "%s: Dim = (%d, %d) is inconsistent with x.size() = %d",
>>                        "ddenseMatrix::ddenseMatrix", nrow, ncol, size
>>                    ) ;
>>            }
>>            ~foo_exception() throw(){}
>> 
>>        private:
>>            int nrow, ncol, size ;
>>    } ;
>> 
>> 
>>    ', plugin = "Rcpp", verbose = TRUE
>> )
>> 
>> 
>>> tryCatch( fy(), error = function(e) writeLines( conditionMessage(e) ) )
>> ddenseMatrix::ddenseMatrix: Dim = (10, 10) is inconsistent with x.size() =
>> 10
>> 
>> 
>> sprintf is a template, and static data is allocated with it. The parameter
>> should be bug enough to host the full message.
>> 
>> one thing you can do is instantiate the template once :
>> 
>> const char* (*my_sprintf)(const char*, ...) = &sprintf<100> ;
>> 
>> Romain
>> 
>> --
>> Romain Francois
>> Professional R Enthusiast
>> +33(0) 6 28 91 30 30
>> http://romainfrancois.blog.free.fr
>> |- http://bit.ly/gpCSpH : Evolution of Rcpp code size
>> |- http://bit.ly/hovakS : RcppGSL initial release
>> `- http://bit.ly/iaxTdO : parser 0.0-12
>> 
>> 
>> _______________________________________________
>> Rcpp-devel mailing list
>> Rcpp-devel at lists.r-forge.r-project.org
>> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
>> 


More information about the Rcpp-devel mailing list