Wednesday, August 24, 2016

Digest for comp.lang.c++@googlegroups.com - 11 updates in 3 topics

Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Aug 24 10:11PM +0100

On 24/08/2016 21:00, Jerry Stuckle wrote:
> transmitting errors of all kinds". Among other things, the overhead of
> exception handling is quite high. And exceptions never were designed to
> handle "all kinds of errors".
 
Again your ignorance is showing. In a decent implementation the
overhead for exception handling is zero for the case of the exception
not being thrown. For recoverable exceptions the overhead of throwing
them is offset by the fact that they shouldn't be thrown very often
(i.e. not on the common/critical code path) but that doesn't mean you
should only use them for non-recoverable conditions.
 
 
> Good programmers know how to use exceptions effectively. Crappy
> programmers misuse them for all kinds of things they weren't meant for.
 
You don't seem to know what exceptions are meant for so according to you
you are a crappy programmer. I wouldn't argue with that.
 
/Flibble
Jerry Stuckle <jstucklex@attglobal.net>: Aug 24 05:28PM -0400

On 8/24/2016 5:11 PM, Mr Flibble wrote:
> them is offset by the fact that they shouldn't be thrown very often
> (i.e. not on the common/critical code path) but that doesn't mean you
> should only use them for non-recoverable conditions.
 
I agree. Your ignorance is showing. As I said - exceptions are for
"exceptional conditions" - not handling expected conditions such as NOT
FOUND from a database or invalid user input. The cost of unwinding the
stack is very high.
 
And I said nothing about using them for non-recoverable conditions.
Those are YOUR WORDS.
 
 
> You don't seem to know what exceptions are meant for so according to you
> you are a crappy programmer. I wouldn't argue with that.
 
> /Flibble
 
Oh, I understand completely what they are for. But you once again show
you are a crappy programmer.
 
No surprise there. And no wonder you can't find a job with a decent
company.
 
--
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Aug 24 10:39PM +0100

On 24/08/2016 22:28, Jerry Stuckle wrote:
> "exceptional conditions" - not handling expected conditions such as NOT
> FOUND from a database or invalid user input. The cost of unwinding the
> stack is very high.
 
Whether or not the cost of unwinding the stack is a concern depends
entirely on the situation in question. In the rare case where it is a
concern then a different approach to the particular problem in question
may be required. You wouldn't throw an exception in order to draw an
individual pixel when rendering a frame buffer for example but this is a
straw man much like your argument. Your words "very high" are entirely
subjective and completely relative.
 
Your basic problem is that you are generalizing without realizing that
you are generalizing.
 
> you are a crappy programmer.
 
> No surprise there. And no wonder you can't find a job with a decent
> company.
 
You do know that attacking the person (ad hominem) is a logical fallacy
right? Do you even know what a logical fallacy is? And when you use
one you have effectively lost the argument?
 
/Flibble
Jerry Stuckle <jstucklex@attglobal.net>: Aug 24 05:58PM -0400

On 8/24/2016 5:39 PM, Mr Flibble wrote:
> subjective and completely relative.
 
> Your basic problem is that you are generalizing without realizing that
> you are generalizing.
 
The cost of unwinding a stack is ALWAYS a concern - at least to a
competent programmer. And it is YOU who are generalizing - and trying
to put words into my mouth. It doesn't work, Flibbie.
 
 
> right? Do you even know what a logical fallacy is? And when you use
> one you have effectively lost the argument?
 
> /Flibble
 
In your case it's not an attack. It's only the truth - as you yourself
have proven time and time again. I can't help it if the truth hurts.
 
--
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Aug 24 11:41PM +0100

On 24/08/2016 22:58, Jerry Stuckle wrote:
 
> The cost of unwinding a stack is ALWAYS a concern - at least to a
> competent programmer.
 
No, it isn't. Donald Knuth once said:
 
"We should forget about small efficiencies, say about 97% of the time:
premature optimization is the root of all evil. Yet we should not pass
up our opportunities in that critical 3%."
 
So we only need to worry about the overhead of throwing exceptions in
that 3% not that 97%.
 
Maybe you should take a course in computer programming?
 
/Flibble
David Brown <david.brown@hesbynett.no>: Aug 25 01:17AM +0200

On 24/08/16 19:35, Öö Tiib wrote:
> Can they manage resources? Resources besides memory? Can they
> handle threads and locks? Etc. C++ without exceptions is no way
> simple and foolproof tool.
 
It is neither simple nor foolproof, whether or not you use exceptions.
Exceptions are just one tool in the C++ toolbox.
 
 
> * The "nothrow" guarantee is marked with "noexcept" specifier in C++.
> Exceptions won't be ever thrown out of such functions. How it can be
> simpler?
 
Note that "noexcept" is from C++11 onwards. The older exception
specifications did not guarantee anything (other than giving the
compiler new ways to make things go wrong for your program if you don't
follow your specifications).
 
But since noexcept (like throw()) is not checked at compile time, it
means manual work - you have to figure out if your function really does
not throw anything, which means figuring out if any of the operators,
function calls, etc., in the function are definitely noexcept.
 
Sure, it can be done - but the effort involved is not negligible. If
the end result is better, safer code, then great. If not, the effort is
wasted, and it's another thing for people to get wrong.
 
> differ from a function that has no side effects (rolls everything back)
> when it returns an error code. So it is special *functionality* and is
> expected to be documented about a function.
 
Having a strong guarantee on a function can definitely be a useful thing.
 
But consider what you are protecting against by this "special design
effort". A sizeable percentage of programs are run on PCs, by humans.
They will /never/ run out of memory, assuming you don't have leaks. The
action on failure, from a general "catch" somewhere in or close to
main(), will be to present an error message and then die. In such
cases, all the extra effort in making strong guarantee functions is
wasted. Worse than that - more code means more opportunities for bugs,
and the complications for the strong guarantee can make code much
slower. And all in the name of avoiding something that will never
happen, and minimising the consequences unnecessarily.
 
And there are lots of systems where errors are simply not acceptable -
exceptions should not be thrown. Then there is not need to throw or
catch exceptions - at best, they are a tool to help during testing and
development.
 
Again, I am not saying it is wrong to use exceptions, or wrong to
provide strong guarantees - just that it comes with a cost that is often
not worth paying.
 
 
> RAII is sufficient for achieving basic guarantee. It does not achieve
> roll-back guarantee automatically on general case, but nothing does
> that. RAII is essential for other reasons anyway, exactly my point.
 
I am quite happy with RAII - it has many uses even without exceptions.
 
>> small embedded systems).
 
> Very small embedded systems and bad quality of some implementations
> are red herrings again.
 
Small embedded systems are programmed in C++ these days. It is a
growing field.
 
> Small systems do trivial things and so usage of most
> features of C++ (including exceptions) are likely overengineering there.
 
True enough.
 
> if we use exceptions or not. It is same as with unskilled workforce, exceptions
> are not *the* issue there and don't stand out as special, something else is
> the issue.
 
Lack of support for exceptions, or inefficient implementations, does not
mean low quality tools.
 
> failed attempt of operation may change it (but we guarantee not to)
> regardless if we throw exception after we failed or we return error code.
> What else you suggest to do on general case?
 
You may well have to make backup copies if you want to write
trial-and-error code, whether or not you use exceptions. But when you
have exceptions, you have to be aware that just about anything can fail
unexpectedly with an exception. Without exceptions, and using explicit
error handling, you know where things can go wrong.
 
> only for to handle exceptional situations (like name indicates).
> That does not mean that such handling itself is rare in code. In mature
> program over half of handled situations are exceptional.
 
My dislike for exceptions is that they hide things that I would prefer
to be out in the open.
 
If I see a function:
 
int foo(int x);
 
I read that as a function that as a function that takes an integer "x",
foo's it, and returns an integer result. It is clear and simple, and
ready to use.
 
But with exceptions, foo is now a function that takes an integer "x",
and /either/ foo's it and returns an integer, /or/ it returns a
completely unexpected object of an unknown type that may not even be
known to the user of foo, which will lead to a jump to somewhere else in
code that the user of foo doesn't know about.
 
If foo is a function that could fail, I prefer to know about it:
 
tuple<int, bool> foo(int x);
 
 
As an aside, I /really/ hope that structured binding makes it into
C++17, so that we can write:
 
auto [result, success] = foo(123);
bitrex <bitrex@de.lete.earthlink.net>: Aug 24 04:12PM -0400

On 08/24/2016 03:53 PM, Victor Bazarov wrote:
> standard container, AFAIK, because being copy-constructible is one of
> the requirements for a contained type, at least in C++ 98.
 
> V
 
I found adding a user-defined copy-constructor that assigns a new
unique_ptr manually seems to work, at least in C++11:
 
template <typename T>
class Foo {
public:
Foo() = default;

Foo(const Foo& foo)
{
baz = std::make_unique<std::vector<T>>(*foo.baz);
}

~Foo() = default;

private:
std::unique_ptr<std::vector<T>> baz =
std::unique_ptr<std::vector<T>>(new std::vector<T>());
};
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Aug 24 10:35PM +0200

On 24.08.2016 21:28, bitrex wrote:
> std::unique_ptr<std::vector<T>> baz =
> std::unique_ptr<std::vector<T>>(new std::vector<T>());
> };
 
Oh my. Much of the point of `std::vector` is that it automates the
memory management. Adding memory management on top of that is, well, not
needed.
 
 
> std::unique_ptr<std::vector<Foo<T>>> bip =
> std::unique_ptr<std::vector<Foo<T>>>(new std::vector<Foo<T>>());
 
> };
 
Ditto, that's just asking for problems.
 
 
> {
> Bar<uint32_t> bar(10);
> return 0;
 
`return 0;` is the default for `main`.
 
 
> to be pushed back into "bip" because it can't use the default
> copy-constructor for that class (as unique_ptrs aren't copyable.) What's
> the correct way to do this?
 
Just use `std::vector` directly.
 
[code]
#include <vector>
#include <stddef.h>
 
template< class Type >
class Foo
{
private:
std::vector<Type> baz;
 
public:
Foo() = default;
~Foo() = default;
};
 
template < class Type >
class Bar
{
private:
std::vector<Foo<Type>> bip;
 
public:
Bar( int const foonum )
: bip( foonum, Foo<Type>() )
{}
 
~Bar() = default;
 
};
 
auto main()
-> int
{
Bar<int> bar{ 10 };
(void) bar;
}
[/code]
 
 
Cheers & hth.,
 
- Alf
mark <mark@invalid.invalid>: Aug 24 11:10PM +0200

You can add a move constructor to Foo:
 
#include <vector>
#include <memory>
 
template <typename T>
class Foo {
public:
Foo() = default;
~Foo() = default;
Foo(Foo&& ) = default;
 
private:
std::unique_ptr<std::vector<T>> baz =
std::unique_ptr<std::vector<T>>(new std::vector<T>());
};
 
template <typename T>
class Bar {
public:
Bar(size_t foonum)
{
for (size_t n = 0; n < foonum; ++n) {
bip->push_back(Foo<T>());
}
}
 
~Bar() = default;
 
private:
std::unique_ptr<std::vector<Foo<T>>> bip =
std::unique_ptr<std::vector<Foo<T>>>(new std::vector<Foo<T>>());
 
};
 
int main()
{
Bar<uint32_t> bar(10);
return 0;
}
Victor Bazarov <v.bazarov@comcast.invalid>: Aug 24 05:15PM -0400

On 8/24/2016 4:12 PM, bitrex wrote:
> std::unique_ptr<std::vector<T>> baz =
> std::unique_ptr<std::vector<T>>(new std::vector<T>());
> };
 
Is that an exercise? What is the reason for using 'std::unique_ptr' in
your design? Is there such a reason? IOW, why do you thinkn you need
specifically 'std::unique_ptr'? Would not 'std::shared_ptr' do? I
cannot tell from the code you showed because there is no design intent
obvious in it. And *that's* why I asked "to do *what*". You still
haven't answered that question, remember?
 
The original application of 'unique_ptr' was to assist in _move_
operations. The owned object is created once, and only destroyed once,
when the final 'unique_ptr' object that "owns" it is destroyed. Between
the creation and the destruction, the ownership is actually transferred.
Splitting responsibilities of 'auto_ptr' between 'shared_ptr' and
'unique_ptr' solved some serious problems, IIRC...
 
V
--
I do not respond to top-posted replies, please don't ask
David Brown <david.brown@hesbynett.no>: Aug 24 09:27AM +0200

On 23/08/16 23:06, mark wrote:
> static constexpr int table[5] = { 4, 1, 7, 2, 1 };
> static constexpr int i = table[2];
> };
 
Pre C++11, these have to be "const" and defined outside the class. If
the class is defined in a header and used in other source that does not
have compile-time access to the table values, you may lose optimisation
opportunities.
 
 
> void A::m() {
> int arr[table[3]];
> }
 
Since "table[3]" is no longer a constant expression, this is not valid
in standard C++ (until C++14, but that doesn't help much!). But it /is/
valid in gcc, which allows variable length arrays as an extension.
Technically, since table[3] is not a constant expression, this is a VLA
- even though the compiler knows exactly what size it will be, and can
generate code using that fact. (gcc 4.3 may not be smart enough to do
so, however.)
 
There will be (or should be) no difference in the generated code between
a VLA with a size known to the compiler, and a "normal" array whose size
is a constant expression. However, you have some restrictions - you
can't make it "static", or file scope, for example.
 
 
> int A::m2(int v) {
> return table[v] * 42;
> }
 
That should be fine with table being a plain "const". The compiler
should be able to optimise this fully if it knows the value of "v" for a
particular call.
 
> return -1;
> }
> }
 
That will not work without constexpr table - even with gcc extensions.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: