By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,189 Members | 933 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,189 IT Pros & Developers. It's quick & easy.

Problem with exceptions, templates and pure virtual functions

P: n/a
Hello,

I need to write a class for exceptions which can be thrown, caught,
stored and thrown once again. I have written the following code:

--- begin ---
#include <string>

class Exception {
public:
virtual ~Exception() throw() {}
virtual const char* what() const throw() = 0;
virtual void raise() = 0;
};

class RuntimeError: public Exception {
public:
RuntimeError(const std::string& what): what_(what) {}
const char* what() const throw() { return what_.c_str(); }
void raise() { throw *this; }
private:
std::string what_;
};

template<class Self, class Baseclass ExceptionImpl: public Base {
public:
typedef ExceptionImpl<Self, BaseImpl;

void raise() { throw *this; }
template<class AExceptionImpl(A a): Base(a) {}
// ExceptionImpl(const Self& self): Base(self) {}
};

class AbstractError: public RuntimeError {
public:
AbstractError(const std::string& what): RuntimeError(what) {}
virtual void foo() = 0;
};

class ConcreteError: public ExceptionImpl<ConcreteError, AbstractError>
{
public:
ConcreteError(const std::string& what): Impl(what) {}
void foo() {}
};

int main()
{
ConcreteError c("foo");
return 0;
}
--- end ---

....and received those strange compiler messages (Microsoft Visual C++
2005):

--- begin ---
Compiling...
exceptions.cpp
c:\src\temp\exceptions\exceptions.cpp : warning C4717:
'ConcreteError::ConcreteError' : recursive on all control paths,
function will cause runtime stack overflow
Linking...
exceptions.obj : error LNK2019: unresolved external symbol "public:
__thiscall ExceptionImpl<class ConcreteError,class
AbstractError>::ExceptionImpl<class ConcreteError,class
AbstractError>(class ExceptionImpl<class ConcreteError,class
AbstractErrorconst &)"
(??0?$ExceptionImpl@VConcreteError@@VAbstractError @@@@QAE@ABV0@@Z)
referenced in function "public: virtual void __thiscall
ExceptionImpl<class ConcreteError,class AbstractError>::raise(void)"
(?raise@?$ExceptionImpl@VConcreteError@@VAbstractE rror@@@@UAEXXZ)
exceptions.obj : error LNK2001: unresolved external symbol "public:
virtual void * __thiscall ExceptionImpl<class ConcreteError,class
AbstractError>::`scalar deleting destructor'(unsigned int)"
(??_G?$ExceptionImpl@VConcreteError@@VAbstractErro r@@@@UAEPAXI@Z)
exceptions.obj : error LNK2001: unresolved external symbol "public:
virtual void * __thiscall ExceptionImpl<class ConcreteError,class
AbstractError>::`vector deleting destructor'(unsigned int)"
(??_E?$ExceptionImpl@VConcreteError@@VAbstractErro r@@@@UAEPAXI@Z)
C:\src\temp\exceptions\Debug\exceptions.exe : fatal error LNK1120: 3
unresolved externals
--- end ---

If I uncomment the commented constructor in ExceptionImpl,
ConcreteError::ConcreteError() stops to be recursive, but what compiler
wants from me when it complains about absence of `scalar deleting
destructor'?

Linker messages disappear if pure virtual function AbstractError::foo()
is removed or replaced with non-pure or non-virtual, or if body of
function ExceptionImpl::raise() is replaced with empty one.

gcc3 seem to handle this without any warnings, so what's wrong with
this code?

Thanks in advance.

Jul 8 '06 #1
Share this Question
Share on Google+
3 Replies


P: n/a
* Dmitry Prokoptsev:
>
template<class Self, class Baseclass ExceptionImpl: public Base {
public:
typedef ExceptionImpl<Self, BaseImpl;

void raise() { throw *this; }
template<class AExceptionImpl(A a): Base(a) {}
// ExceptionImpl(const Self& self): Base(self) {}
};

If I uncomment the commented constructor in ExceptionImpl,
ConcreteError::ConcreteError() stops to be recursive,
The main /technical/ problem here seems to lie in 'throw *this', which
invokes the ExceptionImpl copy constructor (instantiation of
ExceptionImpl). In the case where Base is abstract and causes
ExceptionImpl to be abstract, you're not permitted to instantiate
ExceptionImpl. You can't instantiate an abstract class.

More generally, I don't think this design is good.

Start by deriving from std::runtime_error, and forget the template
stuff; at least make a non-template version work first.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 8 '06 #2

P: n/a

Alf P. Steinbach wrote:
The main /technical/ problem here seems to lie in 'throw *this', which
invokes the ExceptionImpl copy constructor (instantiation of
ExceptionImpl). In the case where Base is abstract and causes
ExceptionImpl to be abstract, you're not permitted to instantiate
ExceptionImpl. You can't instantiate an abstract class.
Ok, but replacing this line with "throw static_cast<Self&>(*this)"
didn't help.
More generally, I don't think this design is good.
Maybe... then could you please give any advices about doing all this
stuff? I just want each exception class to provide functions
"duplicate()" and "raise()" without writing these functions for each
class by hand.
Start by deriving from std::runtime_error, and forget the template
stuff; at least make a non-template version work first.
Of course, in real life all exceptions will be derived from
std::runtime_error, but in code mentioned above that inheritance was
removed to minimize dependencies.

Jul 8 '06 #3

P: n/a

Dmitry Prokoptsev wrote:
Alf P. Steinbach wrote:
The main /technical/ problem here seems to lie in 'throw *this', which
invokes the ExceptionImpl copy constructor (instantiation of
ExceptionImpl). In the case where Base is abstract and causes
ExceptionImpl to be abstract, you're not permitted to instantiate
ExceptionImpl. You can't instantiate an abstract class.

Ok, but replacing this line with "throw static_cast<Self&>(*this)"
didn't help.
that's because that would lead to recursive instantiations.
What I would do is provide a partial specialization of ExceptionImpl
for AbtrsactError and provide a defauly implemnatation of Foo() and
since you are overriding it in ConcreteError any way, that would work
for you.

Though I have to agree with Alf that this is not the best of designs.
>
More generally, I don't think this design is good.

Maybe... then could you please give any advices about doing all this
stuff? I just want each exception class to provide functions
"duplicate()" and "raise()" without writing these functions for each
class by hand.
Start by deriving from std::runtime_error, and forget the template
stuff; at least make a non-template version work first.

Of course, in real life all exceptions will be derived from
std::runtime_error, but in code mentioned above that inheritance was
removed to minimize dependencies.
Jul 8 '06 #4

This discussion thread is closed

Replies have been disabled for this discussion.