Topic: nothrow destructorrs


Author: Michael Kilburn <crusader.mike@gmail.com>
Date: Tue, 17 Apr 2007 09:04:39 CST
Raw View
On Mar 16, 5:23 am, howard.hinn...@gmail.com (Howard Hinnant) wrote:
> But I'd still love to be able to write:
>
>   SomeClass::~SomeClass() static throw() {...}
>

I'd love to have two destructors -- one for normal execution path (1),
another -- when object is destroyed during stack unwinding (due to
exception) (2). By default they should resolve to the same function --
ClassName::~ClassName();
compiler should generate warning/error if (2) 'is'/'happened to be'
not no-throw.

This should fix most 'no-throw destructor' problems and complaints.
Actually I know couple of cases where throwing destructor (1) will fit
nicely...


> One complication is templated code.  You would want some way to detect a
> function's ability to throw and adjust your checking accordingly:

Hmm... I was always  wondering -- what exception specification has
function instantiated from template? I.e. will this function have
implicit no-throw() spec from the compiler's point of view when it is
called from another function?

template<class T> void f(T*) { do_no_throw_operations(); }

If template functions call each other and everyone does use only no-
throw operations -- will this implicit no-throw() spec "spread" across
calls tree? Especially interested in context of GCC, since it will
have greater effect there (since MSVC does not correctly support
standard here).

Bye.
Sincerely yours, Michael.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Richard Smith <richard@ex-parrot.com>
Date: Wed, 11 Apr 2007 21:25:05 CST
Raw View
restor wrote:
> There are more problems with throwing destructors. In the code:
>
>  struct Bad{
>      ~Bad() { throw std::exception(); }
>  };
>
>  int main() {
>      Bad * ptr = new Bad;
>      delete ptr;
>  }
>
> produces a memory leak, as operator delete is never called.

Not necessarily.  See DR 265.

In the current working draft, this is spelt out explicitly and "The
deallocation function is called regardless of whether the destructor for
the object or some element of the array throws an exception".  [5.3.5/7]

--
Richard Smith

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Grizlyk" <grizlyk1@yandex.ru>
Date: Sat, 7 Apr 2007 09:19:14 CST
Raw View
Grizlyk wrote:
>
> > The are no any problems here. According to "throw(type)" declaration of
> > concrete function, all functions, used in the function implementation, must
> > follow the "throw(type)" declaration. And compiler easy can check the
> > correctness, due to compile has know all used declarations of
> > implementation.
>
> Just a quick comment. The standard does allow throwing exception in a
> function with a throw() specification, it just means if the exception
> tries to "leave the function", then (I believe, I haven't got a copy
> of the standard here) unexpected() is called. It is still perfectly
> well-defined, and a compiler shouldn't reject code just because it has
> a throw in a no-throw function.

Agree, this is at least useless agreement - to allow throw any, but
later terminate correct parts of program if you will do throw. In fact
the behaviour is point of producing runtime-errors, because during
compile time wrong throw is allowed, but during run time wrong throw
is error.

--
Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "restor" <akrzemi1@interia.pl>
Date: Tue, 27 Mar 2007 19:01:37 CST
Raw View
There are more problems with throwing destructors. In the code:

 struct Bad{
     ~Bad() { throw std::exception(); }
 };

 int main() {
     Bad * ptr = new Bad;
     delete ptr;
 }

produces a memory leak, as operator delete is never called.
This makes every throwing destructor potentially dangerous as the
class object might be allocated on the free store.

The standard mentions (15.2.3): "If a destructor called during stack
unwinding exits
with an exception, terminate is called (15.5.1). So destructors should
generally catch exceptions and
not let them propagate out of the destructor"

The solution to the problems would be to add additional semantics:
No exception gets out of the destructor body:

  Class::~Class() {
      doSomething();
  }

is semantically equivalent to:

 Class::~Class() {
      try{
          doSomething();
      } catch(...) {};
  }

unless the destructor has a throw-anything ( throw(...) ) exception
specification

This would spoil the code of anyone who likes throwing from
destructors, of course, but we have a workaround  for them: the
explicit throw(...) clause.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "=?iso-8859-1?q?Pedro_Lamar=E3o?=" <pedro.lamarao@gmail.com>
Date: Tue, 27 Mar 2007 19:30:40 CST
Raw View
On 27 mar, 22:01, "restor" <akrze...@interia.pl> wrote:

> The solution to the problems would be to add additional semantics:
> No exception gets out of the destructor body:
>
>   Class::~Class() {
>       doSomething();
>   }
>
> is semantically equivalent to:
>
>  Class::~Class() {
>       try{
>           doSomething();
>       } catch(...) {};
>   }

This violates the principle "you don't pay for what you don't use".

--
 Pedro Lamar   o


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Grizlyk" <grizlyk1@yandex.ru>
Date: Thu, 22 Mar 2007 11:47:26 CST
Raw View
restor wrote:
>
> It is often said that the destructor should not throw.

It is of course wrong limitaion of C++ exceptions implementation.

> Is there any
> attempt to detect throwing destructors at compile-time in C++09?
>
> There had been discussions on the new syntax extensions to statically
> check exception specifications like:

The are no any problems here. According to "throw(type)" declaration of
concrete function, all functions, used in the function implementation, must
follow the "throw(type)" declaration. And compiler easy can check the
correctness, due to compile has know all used declarations of
implementation.

> void fun() static throw(any_type);

I think "throw(any_type)" is always static. What the problem? Nothing. At
least compiler can print warning about possible run-time error due to wrong
exception type.

The main problem here is the fact, that C++ will terminate all correct parts
of program, if during run-time execution unlisted exception will be thrown.

The behaviour is contradicts to idea to divide source of errors and error
handler, because handler never can get control over unlisted exception, we
must to apply special forces to make exception throwing safe for correct
parts of program.

The only correctness is just refuse in your program from excplicit throw
declaration, so due to wrong implementation of exception handling C++ has
exceptions safe only without type.

//original code if there is no "unlisted exception" problem
void voo()
{
    if(err_condition) throw err_type(params);
}

    //"foo" will throw "std::unexpected_exception"
    //instead of call of "terminate()"
    //because external "catch(...)" can exist
void foo()throw()
{
    //"correct_throw" suppress warning
    //warning: "voo" violates "throw()" declaration
    voo() correct_throw;
}

void boo()throw(err_type)
{
    try{

    foo();
    foo();
    foo();

    }catch(...){throw err_type("foo->boo");}
}

//changes due to "double-throw error"
void voo()
{
    if(err_condition) throw err_type(params);
}

void foo()
{
    voo();
}

void boo()
{
    try{

    foo();
    foo();
    foo();

    }catch(...){throw err_type("foo->boo");}
}

Looks like BASIC - no types of exceptions.

Other problem is termination of program due to "double throw", in fact for
reliable code we are forced to reserve some return values as
error_return_value (as for programs without exception). This is only
correctness.

//original code if there is no "double throw" problem
void foo()
{
    if(err_condition) throw err_type(params);
}

void boo()
{
    foo();
    foo();
    foo();
}

//changes due to "double-throw error"

template<class T>
inline void safe_throw<T>(T::params)
{
T   err;
    err.push_to_err_stack();

    if( std::is_uncatched_exception() )return;
    throw err;
}

char  foo()
{
    if(err_condition){ safe_throw<err_type>(params); return 0; }
}

char  boo()
{
    if(!foo())return 0;
    if(!foo())return 0;
    if(!foo())return 0;
}


--
Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Chris Jefferson" <4zumanga@gmail.com>
Date: Thu, 22 Mar 2007 15:55:53 CST
Raw View
On Mar 22, 5:47 pm, "Grizlyk" <grizl...@yandex.ru> wrote:
> restor wrote:
>
> > It is often said that the destructor should not throw.
>
> It is of course wrong limitaion of C++ exceptions implementation.
>
> > Is there any
> > attempt to detect throwing destructors at compile-time in C++09?
>
> > There had been discussions on the new syntax extensions to statically
> > check exception specifications like:
>
> The are no any problems here. According to "throw(type)" declaration of
> concrete function, all functions, used in the function implementation, must
> follow the "throw(type)" declaration. And compiler easy can check the
> correctness, due to compile has know all used declarations of
> implementation.

Just a quick comment. The standard does allow throwing exception in a
function with a throw() specification, it just means if the exception
tries to "leave the function", then (I believe, I haven't got a copy
of the standard here) unexpected() is called. It is still perfectly
well-defined, and a compiler shouldn't reject code just because it has
a throw in a no-throw function.

Chris

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Thu, 22 Mar 2007 23:35:07 GMT
Raw View
on Thu Mar 22 2007, "Chris Jefferson" <4zumanga-AT-gmail.com> wrote:

> Just a quick comment. The standard does allow throwing exception in a
> function with a throw() specification, it just means if the exception
> tries to "leave the function", then (I believe, I haven't got a copy
> of the standard here) unexpected() is called. It is still perfectly
> well-defined, and a compiler shouldn't reject code just because it has
> a throw in a no-throw function.

That's correct.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "restor" <akrzemi1@interia.pl>
Date: Thu, 15 Mar 2007 00:22:48 CST
Raw View
Hi,

It is often said that the destructor should not throw. Is there any
attempt to detect throwing destructors at compile-time in C++09?

There had been discussions on the new syntax extensions to statically
check exception specifications like:

void fun() nothrow;

or:

void fun() static throw();

But it doesn't seem they made it to the standard.
It sounds reasonable to have this sort of check for destructors.
Perhaps no additional syntax is necessary whatsoever, and the code
like:

SomeClass::~SomeClass() {
    std::string message("Destroying");
    std::cerr << message << std::endl;
}

should produce a compile-time error, because string's constructor may
throw a std::bad_alloc that will be emitted out of the destructor, and
in order to compile we would have to write:

SomeClass::~SomeClass() {
    try{
        std::string message("Destroying");
        std::cerr << message << std::endl;
    }
    catch(...){};
}

Although this approach refuses to acknowledge that a throwing
destructor like:

 SomeClass::~SomeClass() {
    try{
        std::string message("Destroying");
        std::cerr << message << std::endl;
    }
    catch(...) {
        if( !std::uncaught_exception() )
            throw;
    };
}

Produces no "termination" problems whatsoever. But does anybody write
code like this?

Also, I noted that to-be-added type_traits library provides meta-
functions:
has_nothrow_constructor,
has_nothrow_copy,
has_nothrow_assign,

but does not provide has_nothrow_destructor.
Does anyone know if there is any attempt to detect throwing
destructors at compile-time in C++09?

Thanks,
&rzej

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Chris Jefferson" <4zumanga@gmail.com>
Date: Thu, 15 Mar 2007 09:50:44 CST
Raw View
On Mar 15, 6:22 am, "restor" <akrze...@interia.pl> wrote:
> Hi,
>
> It is often said that the destructor should not throw. Is there any
> attempt to detect throwing destructors at compile-time in C++09?
>...
> Perhaps no additional syntax is necessary whatsoever, and the code
> like:
>
> SomeClass::~SomeClass() {
>     std::string message("Destroying");
>     std::cerr << message << std::endl;
>
> }
>
> should produce a compile-time error, because string's constructor may
> throw a std::bad_alloc that will be emitted out of the destructo

Personally, I think this example shows why this couldn't be done. It
really wouldn't be feasable to break probably hundreds of programs
that use similar constructs to this.

Futhermore, I suspect many programmers including myself don't tend to
worry about if std::string throws a bad_alloc for a short string,
because if you get in that bad a state then there probably isn't a lot
you can do.

Not saying that is correct behaviour, just I would get very annoyed
having to add try/catches all over the place.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: howard.hinnant@gmail.com (Howard Hinnant)
Date: Thu, 15 Mar 2007 19:23:56 GMT
Raw View
In article <1173954461.575163.268640@n59g2000hsh.googlegroups.com>,
 "Chris Jefferson" <4zumanga@gmail.com> wrote:

> On Mar 15, 6:22 am, "restor" <akrze...@interia.pl> wrote:
> > Hi,
> >
> > It is often said that the destructor should not throw. Is there any
> > attempt to detect throwing destructors at compile-time in C++09?
> >...
> > Perhaps no additional syntax is necessary whatsoever, and the code
> > like:
> >
> > SomeClass::~SomeClass() {
> >     std::string message("Destroying");
> >     std::cerr << message << std::endl;
> >
> > }
> >
> > should produce a compile-time error, because string's constructor may
> > throw a std::bad_alloc that will be emitted out of the destructo
>
> Personally, I think this example shows why this couldn't be done. It
> really wouldn't be feasable to break probably hundreds of programs
> that use similar constructs to this.
>
> Futhermore, I suspect many programmers including myself don't tend to
> worry about if std::string throws a bad_alloc for a short string,
> because if you get in that bad a state then there probably isn't a lot
> you can do.
>
> Not saying that is correct behaviour, just I would get very annoyed
> having to add try/catches all over the place.

I agree that we can't do this implicitly.  But I'd still love to be able
to write:

  SomeClass::~SomeClass() static throw() {...}

Mind you I'm not suggesting full static checking of exception specs.
Just static checking of the nothrow case.

And no, I'm not aware of any proposals for this.

One complication is templated code.  You would want some way to detect a
function's ability to throw and adjust your checking accordingly:

template <class T, class A>
vector<T,A>::erase(iterator p) static throw(has_nothrow_assign<T>::value)
{...}

or something like that...

Love to have it.  I suspect it is more complicated than it looks.

-Howard

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]