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

Douglas Bates bates at stat.wisc.edu
Fri Dec 10 20:33:08 CET 2010


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

> 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