Boost logo

Boost :

From: Narech Koumar (narechk_at_[hidden])
Date: 2005-07-14 08:39:01


Jason, thank you for shedding some light on this issue.

[snip]
>
> The compiler intrinsics are only there to provide the type information that is otherwise
> unavailable. Put another way, for fundamental types, we decided we
don't care what the
> value is (we default to false) since an implementation of type traits
can get the right
> value.
>
> This simplifies the implementation and puts the burden on the library implementation
> which can change more easily than the compiler.
>

I see your point. It seems the library (dinkumware) which ships with
Beta2 does not contain type traits for fundamental types from which one
can extract the correct values for __is_xxx or __has_xxx intrinsics. Is
this going to change in the final release of VC8 or is there another way
of getting the correct TT values for undamental types (besides doing it
yourself)?

>
>>struct A
>>{
>> A() {}
>> A(const A&) {}
>> const A& operator=(const A&) {}
>>};
>>
>>typedef A T;
>>__is_pod(T); // false
>>__has_trivial_constructor(T); // false
>>__has_trivial_copy(T); // false
>>__has_trivial_assign(T); // false
>>__has_trivial_destructor(T); // true
>>__has_nothrow_constructor(T); // false, too conservative
>>__has_nothrow_copy(T); // false, too conservative
>>__has_nothrow_assign(T); // false, too conservative
>>
>>The compiler is too conservative regarding nothrow, it should be able to
>>deduce that constructor, copy and assign can never throw.
>>
>>struct B
>>{
>> B() throw() {}
>> B(const B&) throw() {}
>> const B& operator=(const B&) throw() {}
>>};
>>
>>typedef B T;
>>__is_pod(T); // false
>>__has_trivial_constructor(T); // false
>>__has_trivial_copy(T); // false
>>__has_trivial_assign(T); // false
>>__has_trivial_destructor(T); // true
>>__has_nothrow_constructor(T); // true
>>__has_nothrow_copy(T); // true
>>__has_nothrow_assign(T); // true
>>
>>It seems the compiler needs an explicit nothrow statement in order for
>>ctor, copy and assign to be qualified as nothrow. Presumably the result
>>of nothrow deduction is not fed to the intrinsics correctly in this
>>version.
>>
>>Can someone comment on the above.
>>
>
> You are correct that the compiler _could_ deduce nothrow in your example,
> but in general the compiler couldn't (for example, if the definition
of the
> function is in the current translation unit), and therefore shouldn't
try.
>

I was under the impression that the compiler always performs an attempt
to determine whether a type (including function types) is nothrow, for
all types in a translation unit. If it didn't, it would have to
conservatively assume that any function not declared as an explicit
nothrow may throw an exception, forcing the compiler to enclose each and
every non-nothrow function in implicit try/catch blocks along the entire
call chain (or at least those requiring unwinding); looking at assembler
output for an arbitrary program shows this is not the case. If I
understand correctly the use of try/catch blocks disables certain
optimizations (such as ie inlining etc) which is not good for
performance. My concern is that for types such as this:

template <typename Type>
struct X
{
        Type val;
        X() {}
        X(const Type& in): val(in) {}
};

it is impossible to qualify the ctor and copy as an explicit nothrow
because one can not know with which Type the template is specialized (eg
Type can be a fundamental type, or a UDT with ctor/copy which may
throw). However the compiler has that information at compile-time during
specialization of X with Type. It would be a tremendous benefit for a
library to have such information being exposed through __has_nothrow_xxx
intrinsics because they would provide optimization opportunities with
many uses, for example array construction / uninitialized copy with
rollback semantics.

Thanks,

- NK


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk