release build assertions/verifications

Discussion in 'C++' started by Angel Tsankov, Jan 24, 2006.

  1. I need to make verifications in release builds. If a verification
    fails, an error message should be displayed and the program should be
    aborted. I need this solution to be portable. Then I thought of the
    assert macro - it provides the desired functionality but only if
    NDEBUG is not defined. So, I could write smth like this:

    #if defined NDEBUG
    #undef NDEBUG
    #include <cassert>
    #define NDEBUG
    #else
    #include <cassert>
    #endif

    Unfortunately, NDEBUG could be defined to something meaningful, in
    which case it's value would be lost.

    Can anyone think of some other way to use the assert macro for
    verification?
    What about any other options?

    Regards,
    Angel Tsankov
     
    Angel Tsankov, Jan 24, 2006
    #1
    1. Advertising

  2. Angel Tsankov

    mlimber Guest

    Angel Tsankov wrote:
    > I need to make verifications in release builds. If a verification
    > fails, an error message should be displayed and the program should be
    > aborted. I need this solution to be portable. Then I thought of the
    > assert macro - it provides the desired functionality but only if
    > NDEBUG is not defined. So, I could write smth like this:
    >
    > #if defined NDEBUG
    > #undef NDEBUG
    > #include <cassert>
    > #define NDEBUG
    > #else
    > #include <cassert>
    > #endif
    >
    > Unfortunately, NDEBUG could be defined to something meaningful, in
    > which case it's value would be lost.
    >
    > Can anyone think of some other way to use the assert macro for
    > verification?
    > What about any other options?
    >
    > Regards,
    > Angel Tsankov


    I have implemented my own macros, which are similar to Microsoft's.
    Something like:

    class MyException
    {
    MyException( const char* msg );
    const char* what() const;
    };

    #define VERIFY(cond) if(cond); else throw MyException( #cond )
    #if defined( NDEBUG )
    # define ASSERT(cond) VERIFY(cond)
    #else
    # define ASSERT(cond)
    #endif

    Of course, you can make your VERIFY do something other than throw an
    exception. Remember to use compile-time assertions wherever possible
    instead of run-time assertions.

    Cheers! --M
     
    mlimber, Jan 24, 2006
    #2
    1. Advertising

  3. "mlimber" <> wrote in message
    news:...
    > Angel Tsankov wrote:
    >> I need to make verifications in release builds. If a verification
    >> fails, an error message should be displayed and the program should
    >> be
    >> aborted. I need this solution to be portable. Then I thought of the
    >> assert macro - it provides the desired functionality but only if
    >> NDEBUG is not defined. So, I could write smth like this:
    >>
    >> #if defined NDEBUG
    >> #undef NDEBUG
    >> #include <cassert>
    >> #define NDEBUG
    >> #else
    >> #include <cassert>
    >> #endif
    >>
    >> Unfortunately, NDEBUG could be defined to something meaningful, in
    >> which case it's value would be lost.
    >>
    >> Can anyone think of some other way to use the assert macro for
    >> verification?
    >> What about any other options?
    >>
    >> Regards,
    >> Angel Tsankov

    >
    > I have implemented my own macros, which are similar to Microsoft's.
    > Something like:
    >
    > class MyException
    > {
    > MyException( const char* msg );
    > const char* what() const;
    > };
    >
    > #define VERIFY(cond) if(cond); else throw MyException( #cond )
    > #if defined( NDEBUG )
    > # define ASSERT(cond) VERIFY(cond)
    > #else
    > # define ASSERT(cond)
    > #endif
    >
    > Of course, you can make your VERIFY do something other than throw an
    > exception.


    I want my VERIFY to display a message and abort the program. The
    problem is where to display the message - send it to std::cerr, use a
    message box, file or what? It would also be nice if the solution is
    portable. The assert macro takes care of where to output the message
    and is portable. That's why I'm considering it. However, as I
    mentiond, there is a slight problem with it - its value can get lost
    when I #undef it. So, I'm asking for ideas how to cope with this
    problem. I'd also appreciate any other relevant ideas.
     
    Angel Tsankov, Jan 24, 2006
    #3
  4. Angel Tsankov

    mlimber Guest

    Angel Tsankov wrote:
    > "mlimber" <> wrote in message
    > news:...
    > > Angel Tsankov wrote:
    > >> I need to make verifications in release builds. If a verification
    > >> fails, an error message should be displayed and the program should
    > >> be
    > >> aborted. I need this solution to be portable. Then I thought of the
    > >> assert macro - it provides the desired functionality but only if
    > >> NDEBUG is not defined. So, I could write smth like this:
    > >>
    > >> #if defined NDEBUG
    > >> #undef NDEBUG
    > >> #include <cassert>
    > >> #define NDEBUG
    > >> #else
    > >> #include <cassert>
    > >> #endif
    > >>
    > >> Unfortunately, NDEBUG could be defined to something meaningful, in
    > >> which case it's value would be lost.
    > >>
    > >> Can anyone think of some other way to use the assert macro for
    > >> verification?
    > >> What about any other options?
    > >>
    > >> Regards,
    > >> Angel Tsankov

    > >
    > > I have implemented my own macros, which are similar to Microsoft's.
    > > Something like:
    > >
    > > class MyException
    > > {
    > > MyException( const char* msg );
    > > const char* what() const;
    > > };
    > >
    > > #define VERIFY(cond) if(cond); else throw MyException( #cond )
    > > #if defined( NDEBUG )
    > > # define ASSERT(cond) VERIFY(cond)
    > > #else
    > > # define ASSERT(cond)
    > > #endif
    > >
    > > Of course, you can make your VERIFY do something other than throw an
    > > exception.

    >
    > I want my VERIFY to display a message and abort the program. The
    > problem is where to display the message - send it to std::cerr, use a
    > message box, file or what? It would also be nice if the solution is
    > portable. The assert macro takes care of where to output the message
    > and is portable. That's why I'm considering it. However, as I
    > mentiond, there is a slight problem with it - its value can get lost
    > when I #undef it. So, I'm asking for ideas how to cope with this
    > problem. I'd also appreciate any other relevant ideas.


    My relevant idea was given in the previous post. Just substitute your
    desired behavior for the throwing of the exception. You could output to
    std::cerr and call std::exit, for instance.

    Cheers! --M
     
    mlimber, Jan 24, 2006
    #4
  5. "mlimber" <> wrote in message
    news:...
    > Angel Tsankov wrote:
    >> "mlimber" <> wrote in message
    >> news:...
    >> > Angel Tsankov wrote:
    >> >> I need to make verifications in release builds. If a
    >> >> verification
    >> >> fails, an error message should be displayed and the program
    >> >> should
    >> >> be
    >> >> aborted. I need this solution to be portable. Then I thought of
    >> >> the
    >> >> assert macro - it provides the desired functionality but only if
    >> >> NDEBUG is not defined. So, I could write smth like this:
    >> >>
    >> >> #if defined NDEBUG
    >> >> #undef NDEBUG
    >> >> #include <cassert>
    >> >> #define NDEBUG
    >> >> #else
    >> >> #include <cassert>
    >> >> #endif
    >> >>
    >> >> Unfortunately, NDEBUG could be defined to something meaningful,
    >> >> in
    >> >> which case it's value would be lost.
    >> >>
    >> >> Can anyone think of some other way to use the assert macro for
    >> >> verification?
    >> >> What about any other options?
    >> >>
    >> >> Regards,
    >> >> Angel Tsankov
    >> >
    >> > I have implemented my own macros, which are similar to
    >> > Microsoft's.
    >> > Something like:
    >> >
    >> > class MyException
    >> > {
    >> > MyException( const char* msg );
    >> > const char* what() const;
    >> > };
    >> >
    >> > #define VERIFY(cond) if(cond); else throw MyException( #cond )
    >> > #if defined( NDEBUG )
    >> > # define ASSERT(cond) VERIFY(cond)
    >> > #else
    >> > # define ASSERT(cond)
    >> > #endif
    >> >
    >> > Of course, you can make your VERIFY do something other than throw
    >> > an
    >> > exception.

    >>
    >> I want my VERIFY to display a message and abort the program. The
    >> problem is where to display the message - send it to std::cerr, use
    >> a
    >> message box, file or what? It would also be nice if the solution is
    >> portable. The assert macro takes care of where to output the
    >> message
    >> and is portable. That's why I'm considering it. However, as I
    >> mentiond, there is a slight problem with it - its value can get
    >> lost
    >> when I #undef it. So, I'm asking for ideas how to cope with this
    >> problem. I'd also appreciate any other relevant ideas.

    >
    > My relevant idea was given in the previous post. Just substitute
    > your
    > desired behavior for the throwing of the exception. You could output
    > to
    > std::cerr and call std::exit, for instance.
    >


    Output to std:cerr gets "lost" in GUI-based applications.
     
    Angel Tsankov, Jan 24, 2006
    #5
  6. Angel Tsankov

    mlimber Guest

    Angel Tsankov wrote:
    > "mlimber" <> wrote in message
    > > My relevant idea was given in the previous post. Just substitute
    > > your
    > > desired behavior for the throwing of the exception. You could output
    > > to
    > > std::cerr and call std::exit, for instance.
    > >

    >
    > Output to std:cerr gets "lost" in GUI-based applications.


    The problem is not that cerr is not portable but that GUIs aren't.
    Another portable alternative is writing to a log file, but personally,
    I think throwing an exception that contains the error message (see my
    first post) is the cleanest option. In such a case, you use the same
    error reporting tool in the code, but supply an appropriate handler for
    each platform, e.g.:

    // For some GUI API
    try
    {
    DoSomething();
    }
    catch( const MyException& e )
    {
    DialogBox( string("Error: ") + e.what() + " Terminating." );
    exit( -1 );
    }

    // For some console application
    try
    {
    DoSomething();
    }
    catch( const MyException& e )
    {
    cerr << ""Error: " << e.what() << " Terminating" << endl;
    exit( -1 );
    }

    // For some program with no console attached
    try
    {
    DoSomething();
    }
    catch( const MyException& e )
    {
    ofstream log( "log.txt", ios::app );
    log << ""Error: " << e.what() << " Terminating" << endl;
    exit( -1 );
    }

    Cheers! --M
     
    mlimber, Jan 24, 2006
    #6
  7. "mlimber" <> wrote in message
    news:...
    > Angel Tsankov wrote:
    >> "mlimber" <> wrote in message
    >> > My relevant idea was given in the previous post. Just substitute
    >> > your
    >> > desired behavior for the throwing of the exception. You could
    >> > output
    >> > to
    >> > std::cerr and call std::exit, for instance.
    >> >

    >>
    >> Output to std:cerr gets "lost" in GUI-based applications.

    >
    > The problem is not that cerr is not portable but that GUIs aren't.
    > Another portable alternative is writing to a log file, but
    > personally,
    > I think throwing an exception that contains the error message (see
    > my
    > first post) is the cleanest option.


    The reason why I'd rather avoid this approach is that I am concerned
    about using it in dtors.
     
    Angel Tsankov, Jan 24, 2006
    #7
  8. Angel Tsankov

    mlimber Guest

    Angel Tsankov wrote:
    > "mlimber" <> wrote in message
    > > The problem is not that cerr is not portable but that GUIs aren't.
    > > Another portable alternative is writing to a log file, but
    > > personally,
    > > I think throwing an exception that contains the error message (see
    > > my
    > > first post) is the cleanest option.

    >
    > The reason why I'd rather avoid this approach is that I am concerned
    > about using it in dtors.


    Then, perhaps the best solution is an ostream-based log. You could
    accept an ostream reference or (smart) pointer in your classes'
    constructors, and they could use it to write their messages. Then on
    different platforms, you could pass the ostream-type object (e.g.,
    std::cerr, a std::eek:fstream for a log file, a std::stringstream) that
    best suits that platform.

    Cheers! --M
     
    mlimber, Jan 24, 2006
    #8
  9. "mlimber" <> wrote in message
    news:...
    > Angel Tsankov wrote:
    >> "mlimber" <> wrote in message
    >> > The problem is not that cerr is not portable but that GUIs
    >> > aren't.
    >> > Another portable alternative is writing to a log file, but
    >> > personally,
    >> > I think throwing an exception that contains the error message
    >> > (see
    >> > my
    >> > first post) is the cleanest option.

    >>
    >> The reason why I'd rather avoid this approach is that I am
    >> concerned
    >> about using it in dtors.

    >
    > Then, perhaps the best solution is an ostream-based log. You could
    > accept an ostream reference or (smart) pointer in your classes'
    > constructors, and they could use it to write their messages.


    Well, I'm sorry to tell you but I can see another flaw with your
    suggestion - my class cannot have a default ctor.
     
    Angel Tsankov, Jan 24, 2006
    #9
  10. Angel Tsankov

    mlimber Guest

    Angel Tsankov wrote:
    > "mlimber" <> wrote in message
    > > Then, perhaps the best solution is an ostream-based log. You could
    > > accept an ostream reference or (smart) pointer in your classes'
    > > constructors, and they could use it to write their messages.

    >
    > Well, I'm sorry to tell you but I can see another flaw with your
    > suggestion - my class cannot have a default ctor.


    So what's the problem? If you followed the plan mentioned above, there
    would be no default constructor.

    Cheers! --M
     
    mlimber, Jan 24, 2006
    #10
  11. "mlimber" <> wrote in message
    news:...
    > Angel Tsankov wrote:
    >> "mlimber" <> wrote in message
    >> > Then, perhaps the best solution is an ostream-based log. You
    >> > could
    >> > accept an ostream reference or (smart) pointer in your classes'
    >> > constructors, and they could use it to write their messages.

    >>
    >> Well, I'm sorry to tell you but I can see another flaw with your
    >> suggestion - my class cannot have a default ctor.

    >
    > So what's the problem? If you followed the plan mentioned above,
    > there
    > would be no default constructor.
    >


    This exactly is the problem - my class cannot have a default ctor. A
    default ctor is needed to create an array of objects of a UDT. So, if
    I adopt your plan then I cannot have an array of objects of my class.
     
    Angel Tsankov, Jan 24, 2006
    #11
  12. Angel Tsankov

    mlimber Guest

    Angel Tsankov wrote:
    > "mlimber" <> wrote in message
    > news:...
    > > Angel Tsankov wrote:
    > >> Well, I'm sorry to tell you but I can see another flaw with your
    > >> suggestion - my class cannot have a default ctor.

    > >
    > > So what's the problem? If you followed the plan mentioned above,
    > > there
    > > would be no default constructor.
    > >

    >
    > This exactly is the problem - my class cannot have a default ctor. A
    > default ctor is needed to create an array of objects of a UDT. So, if
    > I adopt your plan then I cannot have an array of objects of my class.


    OIC. I read your previous post to mean that your class *shouldn't* have
    a default constructor. Sorry.

    There are several ways to get around that problem. One is to use a
    std::vector rather than arrays (which are evil) so that you can choose
    a different constructor. See this FAQ:

    http://www.parashift.com/c -faq-lite/ctors.html#faq-10.5

    Another is to use a static member variable to point to the log that can
    be used for all objects of each class. The log could be set at the
    declaration and/or via a static member function, .e.g.:

    class MyClass
    {
    static boost::shared_ptr<ostream> log_;
    public:
    static SetLog( boost::shared_ptr<ostream>& log )
    {
    log_ = log;
    }
    };

    Finally, you could use a (global) singleton log object. See chapter 6
    of _Modern C++ Design_ for copious detail on how to implement such a
    singleton to meet different needs. A simple version might look like:

    template<class T>
    class Singleton
    {
    public:
    static T& Instance();
    private:
    // Disabled functions (no bodies provided)
    Singleton();
    Singleton( const Singleton& );
    Singleton& operator=( const Singleton& );
    Singleton* operator&();
    ~Singleton();
    };

    template<class T>
    T& Singleton<T>::Instance()
    {
    static T myObject;
    return myObject;
    }

    // Assume class Log is defined somewhere
    typedef Singleton<Log> theLog;

    class MyClass
    {
    public:
    // ...
    ~MyClass() { theLog::Instance() << "MyClass destroyed."; }
    };

    Also, see these FAQs for why you shouldn't use arrays polymorphically:

    http://www.parashift.com/c -faq-lite/proper-inheritance.html#faq-21.4
    http://www.parashift.com/c -faq-lite/proper-inheritance.html#faq-21.5

    Cheers! --M
     
    mlimber, Jan 24, 2006
    #12
  13. Angel Tsankov wrote:

    > Can anyone think of some other way to use the assert macro for
    > verification?
    > What about any other options?


    This article might interest you:
    http://www.cuj.com/documents/s=8464/cujcexp0308alexandr/


    Martin

    --
    Quidquid latine scriptum sit, altum viditur.
     
    Martin Eisenberg, Jan 25, 2006
    #13
  14. "Martin Eisenberg" <> wrote in message
    news:-dortmund.de...
    > Angel Tsankov wrote:
    >
    >> Can anyone think of some other way to use the assert macro for
    >> verification?
    >> What about any other options?

    >
    > This article might interest you:
    > http://www.cuj.com/documents/s=8464/cujcexp0308alexandr/
    >


    Yes, it did. Thanks!
     
    Angel Tsankov, Jan 25, 2006
    #14
  15. "Angel Tsankov" <-sofia.bg> wrote in message
    news:43d5e2cd$0$15795$...
    >I need to make verifications in release builds. If a verification
    > fails, an error message should be displayed and the program should
    > be
    > aborted. I need this solution to be portable. Then I thought of the
    > assert macro - it provides the desired functionality but only if
    > NDEBUG is not defined. So, I could write smth like this:
    >
    > #if defined NDEBUG
    > #undef NDEBUG
    > #include <cassert>
    > #define NDEBUG
    > #else
    > #include <cassert>
    > #endif
    >
    > Unfortunately, NDEBUG could be defined to something meaningful, in
    > which case it's value would be lost.
    >


    However, code that tests NDEBUG for specific values has undefined
    behavior (doesn't it?) and should be avoided. Therefore, it should be
    OK to use the #undef-#define trick with NDEBUG, right?
     
    Angel Tsankov, Jan 25, 2006
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. vhdlcohen
    Replies:
    0
    Views:
    1,125
    vhdlcohen
    Dec 1, 2004
  2. anupam
    Replies:
    2
    Views:
    970
  3. Razvan
    Replies:
    4
    Views:
    1,096
    javakid
    Oct 20, 2004
  4. Razvan

    Proper use of assertions

    Razvan, Oct 7, 2004, in forum: Java
    Replies:
    5
    Views:
    519
  5. David Heinemeier Hansson
    Replies:
    0
    Views:
    117
    David Heinemeier Hansson
    Mar 27, 2005
Loading...

Share This Page