Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Destructor call of virtual base class - what happens with exception spec?

Reply
Thread Tools

Destructor call of virtual base class - what happens with exception spec?

 
 
Johannes Schaub (litb)
Guest
Posts: n/a
 
      09-13-2010
I tried to force programmers of a derived class to explicitly define a
constructor (just for fun). This is what i came up with:

struct Viral {
struct Dose { };
protected:
~Viral() throw (Dose) { }
};

struct Base : virtual Viral {
virtual ~Base() throw() { }
};

struct Derived : Base { };

It's an illegal program because Derived::~Derived calls ~Viral, so it
includes (Dose) in its exception spec, but as it overrides ~Base, it will
have a looser exception spec and is this illegal. The user explicitly needs
to overrideit

struct Derived : Base { ~Derived() throw() { } }; // OK

Clang rejects the code with the implicitly defined destructor, but GCC and
comeau online accept it, which surprises me.

Are clang and me right, or are we wrong and the other two are right?

 
Reply With Quote
 
 
 
 
Gil
Guest
Posts: n/a
 
      09-13-2010
On Sep 13, 10:53 am, "Johannes Schaub (litb)" <(E-Mail Removed)>
wrote:
> I tried to force programmers of a derived class to explicitly define a
> constructor (just for fun). This is what i came up with:
>
> struct Viral {
> struct Dose { };
> protected:
> ~Viral() throw (Dose) { }
>
> };
>
> struct Base : virtual Viral {
> virtual ~Base() throw() { }
>
> };
>
> struct Derived : Base { };
>
> It's an illegal program because Derived::~Derived calls ~Viral, so it
> includes (Dose) in its exception spec, but as it overrides ~Base, it will
> have a looser exception spec and is this illegal. The user explicitly needs
> to overrideit
>
> struct Derived : Base { ~Derived() throw() { } }; // OK
>
> Clang rejects the code with the implicitly defined destructor, but GCC and
> comeau online accept it, which surprises me.
>
> Are clang and me right, or are we wrong and the other two are right?


MIOS (my interpretation of standard): you are right;
in your example, implicitly declared Derived::~Derived should come
with an implicit exception specification that is against 15.4/3 with
regard to overriding Base::~Base.
 
Reply With Quote
 
 
 
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      09-13-2010
Balog Pal wrote:

>
> "Johannes Schaub (litb)"
>>I tried to force programmers of a derived class to explicitly define a
>> constructor (just for fun). This is what i came up with:
>>
>> struct Viral {
>> struct Dose { };
>> protected:
>> ~Viral() throw (Dose) { }
>> };
>>
>> struct Base : virtual Viral {
>> virtual ~Base() throw() { }
>> };
>>
>> struct Derived : Base { };
>>
>> It's an illegal program because Derived::~Derived calls ~Viral, so it
>> includes (Dose) in its exception spec, but as it overrides ~Base, it will
>> have a looser exception spec and is this illegal. The user explicitly
>> needs
>> to overrideit
>>
>> struct Derived : Base { ~Derived() throw() { } }; // OK
>>
>> Clang rejects the code with the implicitly defined destructor, but GCC
>> and comeau online accept it, which surprises me.
>>
>> Are clang and me right, or are we wrong and the other two are right?

>
> Does it matter when there is so wide consensus that dtors shall not throw?


Note that none of the constructors above throws. One of them just has a
throw specification that "reserves the right" to throw. The constructor as
shown, however, does not.

I don't know whether there is a consensus about throw-specifications of
constructors.

> And almost that wide to not write exceptions specs?


Sure it matters. Since two compilers disagree on whether the code is well-
formed, we want to know _where_ to file a bug report

> Who would allow those fragments into any real program? I'd definitely not.


Well, his trickery about throw specifications (once thoroughly understood)
is about making the compiler barf at certain inputs and thereby forcing the
client of some library to code in a certain way. Such techniques, per se,
might prove useful in some circumstances; and I cannot rule out that the
"throw-spec-trick" could become part of such a technique.


Best

Kai-Uwe Bux
 
Reply With Quote
 
Balog Pal
Guest
Posts: n/a
 
      09-13-2010

"Kai-Uwe Bux" <(E-Mail Removed)>

>> Does it matter when there is so wide consensus that dtors shall not
>> throw?

>
> Note that none of the constructors above throws. One of them just has a
> throw specification that "reserves the right" to throw. The constructor as
> shown, however, does not.
>
> I don't know whether there is a consensus about throw-specifications of
> constructors.


I was talking about destructors, not constructors. ctors are the best
candidates to throw, as other options to signal a problem are limited or
problematic.

While exceptions escaping dtors can wreak much havoc so many many template
libraries, including STL just call it UB if the subject does so.

Handling the consequences is problematic too -- and the most evil thing is
that call of other destructors gets prevented, killing the ctor/dtor
symmetry most good design builds on in a C++ program.

>> And almost that wide to not write exceptions specs?

>
> Sure it matters. Since two compilers disagree on whether the code is well-
> formed, we want to know _where_ to file a bug report


LOL. Certainly I agree that the standard's verdict is better be clear, and
implementations do it corectly. Just IIRC exception spec is already
deprecated in c++0x -- and some widely used implementations deliberately
make it for different semantics.

>> Who would allow those fragments into any real program? I'd definitely
>> not.

>
> Well, his trickery about throw specifications (once thoroughly understood)
> is about making the compiler barf at certain inputs and thereby forcing
> the
> client of some library to code in a certain way. Such techniques, per se,
> might prove useful in some circumstances; and I cannot rule out that the
> "throw-spec-trick" could become part of such a technique.


Ah, I didn't think about such use. But it seems practice makes its
usability too limited for real practice.

 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      09-14-2010
On Sep 13, 9:52 pm, "Balog Pal" <(E-Mail Removed)> wrote:
> "Johannes Schaub (litb)"


[...]
> Does it matter when there is so wide consensus that dtors
> shall not throw?


There is wide consensus that destructors usually should not
throw. There is even wider consensus that every rule may have
exceptions, and I have at least one class whose destructor
always throws.

> And almost that wide to not write exceptions specs?


Except for empty ones.

--
James Kanze
 
Reply With Quote
 
Vladimir Jovic
Guest
Posts: n/a
 
      09-14-2010
James Kanze wrote:
> On Sep 13, 9:52 pm, "Balog Pal" <(E-Mail Removed)> wrote:
>> "Johannes Schaub (litb)"

>
> [...]
>> Does it matter when there is so wide consensus that dtors
>> shall not throw?

>
> There is wide consensus that destructors usually should not
> throw. There is even wider consensus that every rule may have
> exceptions, and I have at least one class whose destructor
> always throws.


Sounds like a hack. Can you explain why it always throws?
 
Reply With Quote
 
Johannes Schaub (litb)
Guest
Posts: n/a
 
      09-14-2010
Vladimir Jovic wrote:

> James Kanze wrote:
>> On Sep 13, 9:52 pm, "Balog Pal" <(E-Mail Removed)> wrote:
>>> "Johannes Schaub (litb)"

>>
>> [...]
>>> Does it matter when there is so wide consensus that dtors
>>> shall not throw?

>>
>> There is wide consensus that destructors usually should not
>> throw. There is even wider consensus that every rule may have
>> exceptions, and I have at least one class whose destructor
>> always throws.

>
> Sounds like a hack. Can you explain why it always throws?


It may be useful for noreturn functions, i think:

struct noreturn {
~noreturn() {
if(!uncaught_exception())
throw logical_error("dude, why do you return?");
}
};

void myexit() {
noreturn n;
/* magic syscall sex */

}
 
Reply With Quote
 
red floyd
Guest
Posts: n/a
 
      09-14-2010
On Sep 14, 2:59*am, Vladimir Jovic <(E-Mail Removed)> wrote:
> James Kanze wrote:
> > On Sep 13, 9:52 pm, "Balog Pal" <(E-Mail Removed)> wrote:
> >> "Johannes Schaub (litb)"

>
> > * * [...]
> >> Does it matter when there is so wide consensus that dtors
> >> shall not throw?

>
> > There is wide consensus that destructors usually should not
> > throw. *There is even wider consensus that every rule may have
> > exceptions, and I have at least one class whose destructor
> > always throws.

>
> Sounds like a hack. Can you explain why it always throws?


I once saw something like the following nonignorable:

template<typename T>
class nonignorable {
public:
nonignorable(const T& t) : was_read(false), val(t) { }
operator T() const { was_read = true; return val; }
~nonignorable() {
if (!was_read)
throw logic_error("you ignored me!");
}
private:
bool was_read;
T val;
};

The idea was to ensure that a function return value was used,
or explicitly ignored, e.g.:

nonignorable<int> somefunc()
{
// do stuff
return some_integer;
}


 
Reply With Quote
 
red floyd
Guest
Posts: n/a
 
      09-14-2010
On Sep 14, 1:06*pm, red floyd <(E-Mail Removed)> wrote:

Oops: missed a copy constructor and assignment op in there:

> template<typename T>
> class nonignorable {
> * * public:
> * * * * nonignorable(const T& t) : was_read(false), val(t) { }

nonignorable(nonignorable<T>& t) : was_read(false),
val(t.val)
{
t.was_read = true;
}
nonignorable& operator=(nonignorable<T>& t)
{
t.was_read = true;
val = t.val;
return *this;
}

// this should probably be an explicit "get()" op
> * * * * operator T() const { was_read = true; return val; }
> * * * * ~nonignorable() {
> * * * * * * if (!was_read)
> * * * * * * * * throw logic_error("you ignored me!");
> * * * * *}
> * * private:
> * * * * *bool was_read;
> * * * * *T val;
>
> };
>


 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      09-15-2010
On Sep 14, 10:59 am, Vladimir Jovic <(E-Mail Removed)> wrote:
> James Kanze wrote:
> > On Sep 13, 9:52 pm, "Balog Pal" <(E-Mail Removed)> wrote:
> >> "Johannes Schaub (litb)"


> > [...]
> >> Does it matter when there is so wide consensus that dtors
> >> shall not throw?


> > There is wide consensus that destructors usually should not
> > throw. There is even wider consensus that every rule may have
> > exceptions, and I have at least one class whose destructor
> > always throws.


> Sounds like a hack. Can you explain why it always throws?


Because that's its defined semantics.

The class in question is used to support complex error messages
in exceptions. So you write something like:
error() << "xyz = " << xyz;
The function error returns an instance of the class, which
collects the output in a ostringstream, and throws the exception
with the generated output in its destructor. (It's actually
a bit more complicated, since you need support copy for the
return value of error(), and you only throw when the last copy
is destructed. You also have to check for other exceptions in
the destructor, and just let them propagate, without throwing
yours.)

--
James Kanze
 
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
Can abstract base class have V-table?, Will the pointer to virtual destructor be entered into the virtual table? sojin C++ 12 04-07-2006 09:02 AM
curious behaviour in virtual destructor inside base class LAvoisieR C++ 8 10-27-2005 07:40 PM
Explicit destructor calls from inside base class destructor frs C++ 20 09-21-2005 09:22 AM
Format of compiler generated derived destructor when base has 'virtual ~base() throw():" qazmlp C++ 1 04-10-2005 03:09 PM
Virtual destructor for virtual base class? Chunhui Han C++ 2 06-24-2004 10:13 AM



Advertisments