Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

warning C4673: throwing 'ex::traced_error<EX>' the following types will not be considered at the catch site

MSVC 10 and MSVC 9 are both generating a level 4 warning message when compiling my exception framework, although the behavior of the program seems correct. The exception framework is rather large & complex, but I have managed to boil it down to its essence. This is a complete program you can compile & run in VS10

#include <cstdlib>
#include <stdexcept>
#include <string>
#include <iostream>
#include <sstream>
using namespace std;

    namespace ex
    {
        class generic_error : virtual public std::exception
        {
        public:
            generic_error(int thread_id) : thread_id_(thread_id) {}
            const char* what() const throw()
            {
                static std::string msg;
                stringstream ss;
                ss << "generic error in thread #" << thread_id_;
                msg = ss.str();
                return msg.c_str();
            }
            int thread_id_;
        };

        template<class EX>
        class traced_error : virtual public std::exception, virtual public EX
        {
        public:
            traced_error(int line, const EX& ex):   EX(ex), line_(line) { }
            const char* what() const throw()
            {
                static std::string msg;
                stringstream ss;
                ss << "traced error on line " << line_ << " : '" << EX::what() << "'";
                msg = ss.str();
                return msg.c_str();
            }
            int line_;
        };

        template<class EX> traced_error<EX> make_traced_error(int line, const EX& ex)
        {
            return traced_error<EX>(line, ex);
        }
}

    int main()
    {
        try
        {
            throw ex::make_traced_error(__LINE__, ex::generic_error(234));
        }
        catch( const ex::generic_error& gex )
        {
            cout << "gex = " << gex.what();
            return 2;
        }
        catch( const exception& ex )
        {
            cout << ex.what();
            return 1;
        }
    }

When compiling the line throw ex::make_traced_error(__LINE__, ex::generic_error(234)); the compiler emits:

1>hacks_vs10.cpp(51): warning C4673: throwing 'ex::traced_error<EX>' the following types will not be considered at the catch site
1>          with
1>          [
1>              EX=ex::generic_error
1>          ]

One of the goals of this exception library is to append source file information to every thrown exception. I use a macro that evaluates to throw ex::make_traced_error(__FILE_, __LINE__, ex);, but that was not necessary to replicate the compiler warning.

make_traced_error instantiates a template exception class, the template parameter for which is the exception being thrown, in this case generic_error. Obviously if I simply throw a plain generic_error the compiler is happy, but this is not what I want to do.

What is the cause and effect of this warning? Is the compiler wrong, or is my code? I should note a couple things here.

First, when I execute this code it does what I expect it to do. The generic_error catch block is called rather than the general exception block, and the output of the program is:

gex = traced error on line 51 :

Second, when I compile this code with the Comeau online compiler it compiles without error or warning, suggesting to me that my code is Standards-compliant and legal C++. Correct assumption?

'generic error in thread #234'

Finally, I have seen the MS knowledge base article about this warning. But MS's explanation was fully unsatisfactory (it did not explain the cause of the warning), and their resolution is unacceptable -- they say that I should just throw a straight generic_error.

like image 614
John Dibling Avatar asked Aug 27 '10 14:08

John Dibling


1 Answers

The issue is indirectly about the multiple virtual inheritance from std::exception. The compiler gets confused because of it, but forgets to tell you why. :-/

James McNellis is right: the compiler promises to mention a type, but it doesn't. Try without the template:

#include <stdexcept>

class Base: virtual public std::exception {};
class Derv: public Base, virtual public std::exception {};

int main()
{
  try {
    throw Derv();
  } catch (const Base &) {
    return 2;
  } catch (...) {
    return 1;
  }
}

When compiled with level 4 warnings, this says nothing more than:

warning C4673: throwing 'Derv' the following types will not be considered at the catch site

I see the value of warnings. But apparently level 4 is buggy in this case. As all works as expected you could just silence the compiler:

#pragma warning(disable: 4673)

I guess you could report this case as a bug to Microsoft. The compiler should state the type and what the problem is.

like image 190
Michel de Ruiter Avatar answered Sep 20 '22 06:09

Michel de Ruiter