const pointer in a throw list + inheritance

My experiments with exceptions and throw lists in particular lead me into this problem: I can't compile with GCC the following code, which works just fine, if the commented non-const versions get used. Perhaps someone has an idea why can't a pointer to const object be specified? In other code without polymorhism and without inheritance I can specify a const pointer into a throw list and it works... Code here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <iostream>                                                         

using namespace std;

struct throwBase
{               
 throwBase(const char* txt):
 msg(txt)                   
 {                          
   cout << " <throwBase constructed!> ";
 }                                      
                                        
 throwBase(const throwBase& tbr):       
 msg(tbr.read())                        
 {                                      
   cout << " <throwBase copy-constructed!> ";
 }                                           

 virtual ~throwBase()
 {                   
  cout << " <~throwBase!>";                                                                                                                                  
 }                                                                                                                                                           
                                                                                                                                                             
 virtual const char* read() const {cout << " <throwBase read() called> "; return msg;}                                                                       
                                                                                                                                                             
protected:                                                                                                                                                   
 const char* msg;                                                                                                                                            
};                                                                                                                                                           
                                                                                                                                                             
struct throwChild:                                                                                                                                           
public throwBase                                                                                                                                             
{                                                                                                                                                            
 throwChild(const char* txt):                                                                                                                                
 throwBase(txt)                                                                                                                                              
 {                                                                                                                                                           
  cout << " <throwChild constructed!> ";                                                                                                                     
 }                                                                                                                                                           
                                                                                                                                                             
 throwChild(const throwChild& tcr):                                                                                                                          
 throwBase(tcr)                                                                                                                                              
 {                                                                                                                                                           
   cout << " <throwChild copy-constructed!> ";                                                                                                               
 }                                                                                                                                                           

 virtual ~throwChild()
 {                    
  cout << " <~throwChild!>";
 }                          

 virtual const char* read() const {cout << " <throwChild read() called> "; return msg;}
};

struct base
{
 virtual void fx()
  throw(const throwBase*)
  //throw(throwBase*)
 {
  cout << " <entered base::fx> ";
  const throwBase* t = new throwBase(" <throwBase constructed from base> ");
  //throwBase* t = new throwBase(" <throwBase constructed from base> ");
  cout << " <base fx will throw!> ";
  throw t;
  cout << " <will leave base::fx> ";
 }
};

struct child:
public base
{
 virtual void fx()
  throw(const throwChild*)
  //throw(throwChild*)
 {
  cout << " <entered child::fx> ";
  const throwChild* t = new throwChild(" <throwChild constructed from child> ");
  //throwChild* t = new throwChild(" <throwChild constructed from child> ");
  cout << " <child fx will throw!> ";
  throw t;
  cout << " <will leave child::fx> ";
 }
};

int
main()
{
 cout << " <will construct child!> ";
 child c;
 base& childAsBase = c;
 cout << " <will try childAsBase.fx()!> ";
 try{childAsBase.fx();} catch (const throwBase* const tPtr)
 {
  cout << " main got an exception, will read its message: ";
  cout << '[';
  cout << tPtr->read();
  cout << ']';

  delete tPtr;

  cout << " <will leave try!> ";
 }
 cout << " <left try!> ";
 cout << endl;

 return 0;
}


The result of it is:

$ g++ -pedantic -Wall -Wextra -g -O0 exceptions-overriding-heap-case-throw-list.cpp -o exceptions-overriding-heap-case-throw-list
exceptions-overriding-heap-case-throw-list.cpp:72: error: looser throw specifier for ‘virtual void child::fx() throw (const throwChild*)’
exceptions-overriding-heap-case-throw-list.cpp:56: error: overriding ‘virtual void base::fx() throw (const throwBase*)’


Feel free to skip if this was too long...
You're code's difficult to read with your one space indentation. It's not clear what version of the code gave you an error. The error text suggests that you mixed const/non const throws in base/child.
I took a quick look at this and simplified the code to illustrate the issue. I have to say, I'm still thoroughly confused. The below does not compile on my version of g++, BUT, if you remove either the virtual keyword from the fx() methods OR the const keyword from the throw specification, it compiles without complaint. I am assuming this is an issue with g++, but perhaps someone more knowledgeable can spot the error :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct throwBase
{   
};

struct throwChild : public throwBase                                                                                                                                             
{ 
};

struct base
{
	virtual void fx() throw( const throwBase *)
	{		
	}
};

struct child : public base
{
	virtual void fx() throw( const throwChild *)
	{
	}
};

int main()
{
	return 0;
}
Thanks rollie! Anyone can try this with Visual C++ or something non-GCC?
1
2
1>main.cpp(11) : warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
1>main.cpp(18) : warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)


Compiles on Visual Studio 2008.
Well, then looks like I have one bug report to submit... Unless something unexpected gets posted in here in a day...
I'd say to file the bug on VS 2008, but exception specifications should not be used.

GCC is correct: child's fx() must at least specify const throwBase* in its specifier list.

Ok, I'm not 100% sure about the last statement. But I am sure that exception specifications
should not be used.
Last edited on
But I am sure that exception specifications should not be used.

What did you really mean and why?
Exception specifications are deprecated from the language because they are a
maintenance headache and in practice provide no real benefit.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct throwBase
{   
};

struct throwChild : public throwBase                                                                                                                                             
{ 
};

struct base
{
	virtual void fx() throw( const throwBase *)
	{		
	}
};

struct child : public base
{
	virtual void fx() throw( const throwChild *)
	{
	}
};

int main()
{
	return 0;
}



Guys... sorry... I am not able to understand what exception specification means??

is it equivalent to something like this in Java

1
2
3
4
 public void someFunc() throws IOException
       {

       }
By exception specification, jsmith means the throw (...) stuff on the ends of your functions.

Just remove it and don't use it.
(And one other thing... it is recommended to throw by value and catch by (const) reference. Don't
throw pointers.)
Topic archived. No new replies allowed.