James said:
James Kanze wrote:
James Kanze wrote:
[...]
The "meaningless" is obviously hyperbole. But the
presence of undefined behavior in C++ does make reliable
software significantly more difficult, since it reduces
the significence of tests: you can never be sure that the
test didn't pass just because some undefined behavior
happened to work this time.
One of the purposes of tests is to remove undefined
behaviour. But the whole thing goes pear shaped when you
rely on a library which has its own undefined behaviour.
The problem is that formally speaking, you can't test for
undefined behavior, since whatever happens is undefined---it
could work in all your tests and still fail.
That goes without saying, but don't forget where we started,
insertion of an immutable object into a standard container.
It would be possible to assert this in the library code.
It would be possible for a library implementation to define
most or all of the undefined behavior, and check for it.
That depends if the library has undefined behaviour. If the
type of objects stored in a container is required to be copy
constructable and assignable, that can be tested.
I'm not sure we're on the same wave length. There are two
issues, and I'm not really sure which one we're talking about.
The first: in specific cases (library or not), C++ has undefined
behavior. You cannot reliably test whether your code falls into
one of those cases or not unless the implementation has defined
the behavior in some specific way you can test for. Two good
examples: instantiating an std::list over a type which doesn't
support assignment (which will never in fact fail with some
implementations of std::list), and something like i++ + ++i (in
which case I know of no implementation where it will "fail", but
it won't always give the same results). In my opinion, such
undefined behavior seriously reduces the confidence we can have
in our tests, and C++ really should try to close as many of
these holes as possible.
The second is the case of library implementors themselves. The
standard says that in certain cases (e.g. std::string(NULL)),
the library has undefined behavior. If, as an implementor, you
define this behavior (e.g. by guaranteeing an assertion
failure), you can and should test for it. But if you decide not
to do so, what does it even mean to test it? Does it have any
meaning to test to ensure that you haven't accidentally defined
any behavior, and if so, how do you test it? Again, in general,
my opinion is that you shouldn't define such cases; that as a
library implementor, you should define the behavior regardless
of what the client code does. But performance considerations
can intervene; checking for null in std::string(char const*)
isn't that expensive, but tracking iterators to verify their
validity can definitely have a measurable impact on performance.
The test might have to be done at the build level, a
verification that compilation fails if this requirement is
violated.
Concept checking, in sum. Some standard library implementations
(g++, and maybe also Dinkumware) implement concept checking
already. The next version of the standard will introduce
language support for this, and require the library to use it (I
think). A lot less undefined behavior, and a major step
forward.
I was thinking along the lines of:
#include <utility>
#include <list>
template < typename T >
struct CheckTypeIsAssignable : std::list<T>
{
CheckTypeIsAssignable()
{
T t;
t = T();
}
};
int main()
{
CheckTypeIsAssignable<std:
air<const int, const int> > c1;
return 0;
}
int main()
{
CheckTypeIsAssignable<std:
air<const int, const int> > c1;
return 0;
}
I'm not quite sure what you're trying to show in this example.
It doesn't test the library in anyway (at least that I can see),
and it doesn't test your code (i.e. verifying that you haven't
instantiated std::list over a type which isn't assignable).
Such concept checks have to be part of the library to be useful.
(Thus, g++ does do something like this when you instantiate an
So you'd agree with me that C++ should eliminate undefined
behavior as far as possible.