Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Problem with exceptions, templates and pure virtual functions

Reply
Thread Tools

Problem with exceptions, templates and pure virtual functions

 
 
Dmitry Prokoptsev
Guest
Posts: n/a
 
      07-08-2006
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 Base> class ExceptionImpl: public Base {
public:
typedef ExceptionImpl<Self, Base> Impl;

void raise() { throw *this; }
template<class A> ExceptionImpl(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
AbstractError> const &)"
(??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.

 
Reply With Quote
 
 
 
 
Alf P. Steinbach
Guest
Posts: n/a
 
      07-08-2006
* Dmitry Prokoptsev:
>
> template<class Self, class Base> class ExceptionImpl: public Base {
> public:
> typedef ExceptionImpl<Self, Base> Impl;
>
> void raise() { throw *this; }
> template<class A> ExceptionImpl(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?
 
Reply With Quote
 
 
 
 
Dmitry Prokoptsev
Guest
Posts: n/a
 
      07-08-2006

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.

 
Reply With Quote
 
amparikh@gmail.com
Guest
Posts: n/a
 
      07-08-2006

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.


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Passing a class to a pure virtual function (without templates) captaincurk@googlemail.com C++ 4 04-22-2009 06:38 PM
private virtual functions and pure virtual functions with bodies John Goche C++ 10 12-08-2006 04:00 PM
How to compile C++ program with templates to pure C or C++ program without templates? PengYu.UT@gmail.com C++ 5 10-12-2005 06:47 PM
Pure functions still pure after definition Todd Aspeotis C++ 3 05-30-2005 03:53 AM
Re: problem with overloaded pure virtual functions Greg Comeau C++ 1 01-19-2005 03:07 PM



Advertisments