New-Style Casts

62 просмотра
Перейти к первому непрочитанному сообщению

James Slaughter

не прочитано,
3 авг. 1998 г., 03:00:0003.08.1998
Forgive me for asking what must be a common question, but can someone
provide a simplified definition of dynamic_cast, static_cast, const_cast
and
reintepret_cast to that found in the old public draft standard?

I am particularly interested in the difference between these and the
old, C
style casts... I've read that only the new style should be used in new
code... not a problem, but why? When should I use which? How does it
affect
class member cast functions?, such as:

class Foo {
public:
operator int ();
};

As I understand it, the following definitions apply... please correct me
where I'm wrong, or enlighten me as to further details:

All casts return a null pointer of the specified type when they fail, or
if
the original argument was null, except when the specified result type is
a
reference, when the exception bad_cast is thrown (should I always check
for
this?)

A const is a const is a const... :) none of the casts affect this?

The cast an be treated like a function call, with regards to
LValue/RValue
stuff (if converted to a reference, it can be an LValue?)

'reinterpret_cast' is for doing slightly dodgy conversions, like casting
to
a different type of function, or converting a char* to an int*, in order
to
read a DWORD (32bit). 'reinterpret_cast' is machine and implementation
dependant, not guaranteed to be two-way, and generally equivelent to a C
style cast.

'dynamic_cast' is for taking a pointer to a base class, and casting it
to a
derived type. It will fail if the original value was not the specified
type,
or does not have a dynamic type that is, or had as a base (?), the class
specified. Presumably it can also cast to a base type... how is multiple
inheritance handles?

'static_cast' can modify the type of an expression as well as a value?
It
seems to guarantee not to change the value of a pointer, but what else
does
it do?

'const_cast' confuses me even more than static_cast. Please help :)

Thanks for spending the time to read all this... any help is greatly
appreciated.

Regards,
James Slaughter.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Paul Grealish

не прочитано,
4 авг. 1998 г., 03:00:0004.08.1998
James Slaughter wrote:
>
> Forgive me for asking what must be a common question, but can someone
> provide a simplified definition of dynamic_cast, static_cast, const_cast
> and reintepret_cast to that found in the old public draft standard?

Here's a snippet from my Company's coding standards document
that might help:

6.2.17 Prefer C++ style casts
The C language provides a single cast operator '(new-type)var'
that is used for all types of casts. C++ provides four new
cast operators that should always be used (with one exception,
explained below) in preference to old C style casts.
The new C++ cast operators are: static_cast, const_cast,
dynamic_cast and reinterpret_cast. They are preferred for
two reasons:
a) Their use makes it explicit what type of cast is being performed
b) The dynamic_cast cast has desirable functionality not provided
by C style cast.

A few words on each flavour of cast will make their use clearer.
static_cast is used to cast from one basic type to another. It
does not have as much power as C style cast and in some cases a
reinterpret_cast, that explicitly casts between totally unrelated
types, may be necessary. Use of reinterpret_cast should be rare.
Casting away const may only be done with the const_cast.
Down-casting (the explicit cast of a base class reference or
pointer to a derived class) should be performed using the
dynamic_cast operator. Although allowed, dynamic_cast should never
be applied to a reference since, due to the operators inability to
signal a cast failure, the RTL will throw a 'bad_cast' exception.
For reasons explained elsewhere in this document (section 8.7),
exceptions should be avoided where there is some other way to signal
errors to calling code.
The exception, where a C style cast should be used, is when the
result of a function is being 'thrown away'. In this case, use
of the C++ equivalent static_cast tends to obfuscate the code.
Appendix D shows some example code using the new cast operators.
See [12, Item 2] for a more detailed explanation on the purpose
and use of the new cast operators.

[12] Scott Meyers "More Effective C++" Addison-Wesley
ISBN: 0-201-63371-X

Appendix D. Example Code Using C++ Style Cast Operators

#include <cassert>
#include <memory>
#include <string>
#include <iostream>

using namespace std;

//
// Illustrate use of new C++ style casts.
//
class Base { public: virtual ~Base(void) { } };
class Derived1 : public Base { };
class Derived2 : public Base { };
class Unrelated { };

int main(void)
{
//
// Casting away constness
//
const int i = 42;
int* pi_1 = (int*)&i; // Traditional C-style cast

#if 0 // Neither of these two casts will work - must use 'const_cast'
int* pi_2 = static_cast<int*>(&i);
int* pi_3 = reinterpret_cast<int*>(&i);
#endif
int* pi_4 = const_cast<int*>(&i);

//
// Down-casting
//
Base* pD1 = new Derived1;
assert(dynamic_cast<Derived2*>(pD1) == NULL);
assert(dynamic_cast<Derived1*>(pD1) != NULL);

//
// Reinterpret cast
//
Derived1 derived1;
#if 0 // Won't work - requires 'reinterpret_cast'
Unrelated* pUnrelated_1 = static_cast<Unrelated*>(&derived1);
#endif
Unrelated* pUnrelated_2 = reinterpret_cast<Unrelated*>(&derived1);

//
// static cast
//
int* pi;
void* vp = pi;
char* pch = static_cast<char*>(vp);

//
// C-style cast - used when discarding function return.
//
string sHello("Hello");
(void)sHello.size(); // Throw away function return

return 0;
}


--
+---------------------------------+
| Paul Grealish |
| GEOPAK-TMS Limited |
| Cambridge, England |
| paul.g...@uk.geopak-tms.com |
+---------------------------------+

dietma...@claas-solutions.de

не прочитано,
4 авг. 1998 г., 03:00:0004.08.1998
Hi,
In article <902089779.11559.0...@news.demon.co.uk>,

"James Slaughter" <James.S...@susano.demon.co.uk> wrote:
> Forgive me for asking what must be a common question, but can someone
> provide a simplified definition of dynamic_cast, static_cast, const_cast
> and
> reintepret_cast to that found in the old public draft standard?

The four new-style casts are intended to replace the old-fashioned cast.
The
major reason was that with only one cast it hard to see what is actually
going on. For example, the machinery involved in 'dynamic_cast<>()' is
non-trivial and can be too expansive to do in certain cases. On the other
hand, the difference whether the equivalent of 'static_cast<>()' or
'dynamic_cast<>()' is done, may depend on a class having virtual functions.

Anyway, here is what the cast operators are for:
- 'const_cast<>()' is definitely the simplest of them: it can only be used
to
add or remove const (or volatile) to a type. No other type conversion is
allowed in a 'const_cast<>()'.

- 'dynamic_cast<>()' is used to navigate within the inheritance hierarchy.
It
can be used to cast to a more specialized type provided that the base type

has at least one virtual function. 'dynamic_cast<>()' can also be used to
navigate to a sibling type in an object involving multiple inheritance. In
any case, the argument to 'dynamic_cast<>()' has to be a pointer or a
reference. If it has pointer type, the result is '0' on failure; if it is
of
reference type, a 'bad_cast' is thrown instead.

- 'static_cast<>()' can be used to convert between types using the
conversion
operators or the conversion constructors, whatever is applicable. Also,
'static_cast<>()' can be used to convert between fundamental built-in
types
and between enumeration types. It can be used to do the inverse of most
standard conversions (some obvious restriction have to be obeyed). It can
be
used to cast up in an inheritance and even to cast down. However, if a
downcast is done and the object is not of the appropriate type, the
result
is undefined.

- 'reinterpret_cast<>()' covers all remaining applications which could be
done
with the old fashioned cast. ALL conversion done with
'reinterpret_cast<>()'
are implementation dependent. Typical conversions are eg. between 'int*'
and
'char*' or between different types of function pointers (ugh! be
extremely
careful with these one: it basically does not work...).

> I am particularly interested in the difference between these and the
> old, C
> style casts... I've read that only the new style should be used in new
> code... not a problem, but why?

Isn't this covered in the D&E? One of the reasons is readability: The cast
explicitly says what it is intended to do. Also, if you know exactly what
type
an object has, it can be much more efficient to do a downcast: Using
'static_cast<>()' instead of 'dynamic_cast<>()' tells the compiler (and if
you
are wrong, you are lost, of course). If there were only one cast, it would
not
be possible to tell the compiler that it can do some extra optimization.

> All casts return a null pointer of the specified type when they fail, or
> if
> the original argument was null, except when the specified result type is
> a
> reference, when the exception bad_cast is thrown (should I always check
> for
> this?)

No. This only holds for 'dynamic_cast<>()'. All casts complain if they
cannot
be applied (eg. 'reinterpret_cast<>()' cannot be applied to do one of the
conversion done by one of the other casts) at compile time. However, this
does not mean that they will succeed: If you do an invalid downcast with
'static_cast<>()', the program will simply fail.

> A const is a const is a const... :) none of the casts affect this?

'const_cast<>()' can be used to remove 'const' from an object which is not
constant. If it is a constant, the program will simply fail. Thus, you
should
be careful to use 'const_cast<>()' for removing of 'const' only in
situations
where you know that the original objects is not a constant.

> 'reinterpret_cast' is for doing slightly dodgy conversions, like casting
> to
> a different type of function, or converting a char* to an int*, in order
> to
> read a DWORD (32bit). 'reinterpret_cast' is machine and implementation
> dependant, not guaranteed to be two-way, and generally equivelent to a C
> style cast.

C style cast can be done for things done with 'static_cast<>()', too.
'reinterpret_cast<>()' cannot. This cast only for the stuff which really
not
safe.
--
<mailto:dietma...@claas-solutions.de>
homepage: <http://www.informatik.uni-konstanz.de/~kuehl>

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum

Paul D. DeRocco

не прочитано,
4 авг. 1998 г., 03:00:0004.08.1998
James Slaughter wrote:
>
> Forgive me for asking what must be a common question, but can someone
> provide a simplified definition of dynamic_cast, static_cast,
> const_cast and reintepret_cast to that found in the old public draft
> standard?
>
> I am particularly interested in the difference between these and the
> old, C style casts... I've read that only the new style should be used
> in new code... not a problem, but why?

1) const_cast can only change const-ness and volatile-ness, any number
of levels deep in a chain of pointers. For instance, a const pointer to
a const pointer to a const pointer to a char can be converted to a
pointer to a pointer to a pointer to a char.

2) static_cast can only do conversions that can be done automatically in
reverse, other than what const_cast can do. For instance, since a
Derived* can be automatically converted to a Base*, static_cast can
convert a Base* back into a Derived*, although it doesn't verify the
validity of the conversion. Also, since an enumeration can be
automatically converted to an int, static_cast can convert an int into
an enumeration. They are also useful for conversions that could be done
automatically, but aren't in a particular situation, such as converting
an int to a float.

3) dynamic_cast works like static_cast on non-polymorphic types. But if
it is used to cast a pointer or reference to a class with virtual
functions, it can verify the validity of the conversion, and even do
casts among sibling base classes in a multiple-inheritance situation. It
relies upon the same underlying mechanisms as run-time type
identification (RTTI).

4) reinterpret_cast is a non-portable request to reinterpret the bit
pattern. For instance, this is the only new-style cast that will convert
from an int to a pointer, or vice versa. You also have to use
reinterpret_cast to convert from a char* to an unsigned char* or vice
versa.

Your own definitions are close, except for the following:

> All casts return a null pointer of the specified type when they fail,
> or if the original argument was null, except when the specified result
> type is a reference, when the exception bad_cast is thrown (should I
> always check for this?)

This is only true for dynamic_cast. The other casts are unconditional
compiler constructs that don't do any checking at run-time, other than
to skip pointer offsetting if the pointer is null.

> A const is a const is a const... :) none of the casts affect this?

const_cast affects it, as described above.

> 'reinterpret_cast' is for doing slightly dodgy conversions...and


> generally equivelent to a C style cast.

Yes to the first part. A C cast may be the equivalent of static_cast,
const_cast or reinterpret_cast, or some combination thereof.

The usual argument for never using a C-style cast is that casts are
trouble-prone, and therefore the sort of thing you want to be able to
look for. The new-style casts can easily be found by grepping, or
searching with an editor, while the old-style ones can't. However, there
are some casts that are so self-evidently okay that I use C casts. Well,
actually, I prefer the C++ functional notation casts, as long as the
types are single words. For instance, I see no problem using them in
numeric expressions:

float ratio(int x, int y) { return float(x) / float(y); }

--

Ciao,
Paul

Larry Brasfield

не прочитано,
4 авг. 1998 г., 03:00:0004.08.1998
[To moderator: I know this is long. Please forgive this once.]

James Slaughter wrote in message
<902089779.11559.0...@news.demon.co.uk>...


>Forgive me for asking what must be a common question, but can someone
>provide a simplified definition of dynamic_cast, static_cast, const_cast
>and reintepret_cast to that found in the old public draft standard?
>
>I am particularly interested in the difference between these and the
>old, C style casts... I've read that only the new style should be used in new

>code... not a problem, but why? When should I use which? How does it
>affect class member cast functions?, such as:
>
>class Foo {
> public:
> operator int ();
>};
>
>As I understand it, the following definitions apply... please correct me
>where I'm wrong, or enlighten me as to further details:

Sorry to clip your whole set, but I recently had cause to
prepare this more studied and correct version to help
promote proper casting. Any corrections are welcome.


When you write a C-style cast, the compiler
implicitly translates it into some combination
of these distinct casting operations:
- static_cast<new_type>(expr)
(value type change or inheritance traversal)
- const_cast<new_cv_type>(expr)
(discarding or adding cv qualifiers)
- reinterpret_cast<whatever>(something)
(whatever you say, boss, is like TRUTH now)

Usually, when we write such a cast, we know
exactly which of those operations is intended.
There are problems even in that case. (1) The
actual operation can inadvertently change later
when typedef's or type declarations change, or
the type of a casted expression changes. What
had been a simple, relatively safe static_cast
can become a probably bad reinterpret_cast,
without the affected statement even undergoing
an edit. Or a cast intended only to undo const
can become a static_cast or reinterpret_cast,
introducing needless value conversion or the
same problems with reinterpret_cast. Almost any
accidental reinterpret_cast of a pointer is a
recipe for disaster. (2) You may know what cast
operation you wrote, and I know what I meant to
happen, but these intentions are much less clear
when we read each other's code. Modern C++
casts are explicit and there is no question as
to what they mean, once you know what they mean.

So what do they mean, then?

static_cast<new_type>(value_expression)
means convert the value expression, which must be
an r-value, to a value of the new type using the
defined (by C++ or code) conversion operators.
If no legal conversion sequence is defined, then
a compilation error results. This can result in
(accidental, silent) slicing for object upcasts.

static_cast<new_type *>(pointer_expression)
means treat the pointer value as if it points to
the new type, applying whatever adjustments may be
required by traversing an inheritance hierarchy.
If no legal traversal is defined, then this will
result in a compilation error. (This will never
result in a reinterpret_cast.)

static_cast<new_type &>(reference_expression)
same as for pointers, with reference semantics

const_cast<new_cv_ref>(ref_expression)
means alter cv-qualifiers (const and volatile)
to make the ref_expression (a reference or
pointer expression) conform to the type spelled
out as new_cv_ref. If the type change cannot be
effected by only adding or removing cv-qualifiers,
a compilation error results. This cannot silently
become any of the other kinds of cast.

reinterpret_cast<whatever *>(some *)
means treat some pointer as a pointer to
whatever the programmer demands. No kind
of adjustment or check, at compile time or
runtime is performed. The compiler simply
treats the result as having whatever type.
This cannot add or remove cv-qualifiers, nor
can it effect value conversions, nor will it
effect the adjustments often required for a
correct inheritance hierarchy traversal. A
reinterpret_cast is inherently low-level,
almost always implementation dependent and
dangerous, and is rarely necessary in C++.

reinterpret_cast<integer_expression>(some *)
reinterpret_cast<whatever *>(integer_expression)
means convert pointers to or from integers
This is even more rarely needed in C++. This
cast normally preserves the bit pattern.

In addition to the above, which were always available
in C (albeit dangerously), C++ adds this new cast:

dynamic_cast<derv_class *>(base_class_ptr_expr)
means use run-time-type-information (RTTI) to
convert one class pointer to another, giving
a result of 0 if the actual object type is not
compatible with the derv_class type, otherwise
giving the same result as would a static_cast.
(RTTI is only possible when at least one virtual
method is in effect for the base class.)

dynamic_cast<derv_class &>(base_class_ref_expr)
same as for pointers, except with reference
semantics and instead of giving a 0 result
throws an exception of type std::bad_alloc

With use of the above casts, it is never
necessary to resort to C-style casts and
by using them, your code will be clearer
and less subject to later breakage.

--Larry Brasfield
Above opinions may be mine alone.
(Humans may reply at unundered larry_br@sea_net.com )

jka...@otelo.ibmmail.com

не прочитано,
4 авг. 1998 г., 03:00:0004.08.1998
> Forgive me for asking what must be a common question, but can someone
> provide a simplified definition of dynamic_cast, static_cast, const_cast
> and
> reintepret_cast to that found in the old public draft standard?
>
> I am particularly interested in the difference between these and the
> old, C
> style casts... I've read that only the new style should be used in new
> code... not a problem, but why?

Not everyone is so strict. I still use old style casts for explicit
construction of a temporary, for example (e.g. (int)( someValue )).
The real place where the new style casts are important is when casting
pointers and references.

> When should I use which? How does it
> affect
> class member cast functions?, such as:
>
> class Foo {
> public:
> operator int ();
> };

Such functions can only be invoked by the static_cast. None of the others
apply. Often, such functions will be seen as explicitly creating a
temporary, and some people will still prefer the old style casts for
this.

> As I understand it, the following definitions apply... please correct me
> where I'm wrong, or enlighten me as to further details:
>

> All casts return a null pointer of the specified type when they fail, or
> if
> the original argument was null, except when the specified result type is
> a
> reference, when the exception bad_cast is thrown (should I always check
> for
> this?)

No. All casts will return a null pointer if the original value was a
null pointer. Only dynamic_cast will return one otherwise. Only
dynamic_cast does run-time checks, and can throw. When considering
casts between pointers or references, I think the following consideration
would describe the situation:

reinterpret_cast< A* >( ptrB )
The compiler thinks that ptrB points to a B. I'm telling it that the
object at the same physical address is actually an A. In sum, I'm
telling the compiler that what it knows is wrong. A reinterpret_cast
between pointers is always legal (since I'm telling the compiler that
what it knows is completely wrong).

static_cast< A* >( ptrB )
The compiler thinks that ptrB points to a B, which might be a sub-
object of an A. I'm telling the compiler that I know that this
particular B is a subobject of an A, and that it should convert the
pointer to point to the A object. A static_cast between pointers is
only legal if one of the pointers is void*, or if one of the types
inherits from the other.

dynamic_cast< A* >( ptrB )
The compiler thinks that ptrB points to a B, which might be a sub-
object of an A (or, I think, which might be a sub-object of an object
which also derives from an A). I'm telling the compiler that I agree,
but I'm not sure, and would like it to generate a run-time check -- if
the full object contains a base class A, I get a pointer to the A sub-
object of the complete object, otherwise, I get a null pointer.
A dynamic_cast is only legal if both pointers have the same type, or
the source pointer points to an object with at least one virtual
function.

const_cast is simpler to understand -- it can do nothing but change
the const/volatile qualifiers of a pointer or reference.

Casts involving references work in a similar manner, except that the
error condition in dynamic_cast is signaled by an exception, rather
than a null pointer.

The static_cast can also be used for all of the older "value type
conversions", e.g. double->int, etc.

> A const is a const is a const... :) none of the casts affect this?

Except const_cast.

> The cast an be treated like a function call, with regards to
> LValue/RValue
> stuff (if converted to a reference, it can be an LValue?)

Correct. The results of a cast (regardless of type) is an lvalue if and
only if it is a reference.

> 'reinterpret_cast' is for doing slightly dodgy conversions, like casting
> to
> a different type of function, or converting a char* to an int*, in order
> to
> read a DWORD (32bit). 'reinterpret_cast' is machine and implementation

> dependant, not guaranteed to be two-way, and generally equivelent to a C
> style cast.

With the exception of the last statement, yes. Basically, the
interpretation
of a C style cast is: static_cast, if legal, otherwise reinterpret_cast,
possibly followed by a const_cast.

> 'dynamic_cast' is for taking a pointer to a base class, and casting it
> to a
> derived type. It will fail if the original value was not the specified
> type,
> or does not have a dynamic type that is, or had as a base (?), the class
> specified. Presumably it can also cast to a base type... how is multiple
> inheritance handles?

More or less correct. Dynamic_cast involves run time type checking.

Multiple inheritance is handled. Multiple inheritance is also handled
in the case of static_cast (and with C style casts, for that matter).

An interesting experiment would be to define the following hierarchy:

struct L { int l ; virtual ~L() ; } ;
struct R { int r ; virtual ~R() ; } ;
struct D : L , R { int d ; } ;

D aD ;
D* pd = &aD ;
L* pl = &aD ;
R* pr = &aD ;

Finally, try outputting the pointers cast to void* (to see the physical
address they contain), then using the different casts (C style cast,
reinterpret_cast, static_cast and dynamic_cast) to different types.
Note in particular that static_cast< L* >( pr ) will fail at compile
time, and that (R*)( pd ) and (R*)( pl ) have different semantics (which
is one of the principal arguments why we need the new style casts).
You might also want to repeat the experiment adding a virtual base B
to both R and L, and see what happens.

> 'static_cast' can modify the type of an expression as well as a value?

Static_cast is what is typically understood by a conversion. In fact,
reinterpret_cast may also involve a conversion (since the size of the
two pointers may be different), but is intended to implement what is
traditionally called type punning. On most modern machines, it will
give the same results as writing to one element of a union of pointers
and reading from another.

> It
> seems to guarantee not to change the value of a pointer, but what else
> does
> it do?

See above: it tells the compiler that the compiler is stupid. Don't use it
unless you really are absolutely sure that you know more than the compiler
(and thus, more than the people who wrote the compiler, or who designed
the language). It is NOT guaranteed not to change the value of a pointer;
on some architectures, for example, a char* will have more bits that an
int*, and it will be impossible to convert a char* to an int* without
changing the value. The intent, however, is that the resulting pointer
designate the same physical location as the original pointer, if possible.

> 'const_cast' confuses me even more than static_cast. Please help :)

And yet, const_cast is the simplest. If pB is B [const|volatile]*, then
const_cast< T* >( pB ) is legal if an only if T is also B
[const|volatile]*.

--
James Kanze +33 (0)1 39 23 84 71 mailto: ka...@gabi-soft.fr
+49 (0)69 66 45 33 10 mailto: jka...@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orientée objet --
-- Beratung in objektorientierter Datenverarbeitung

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Christopher Eltschka

не прочитано,
4 авг. 1998 г., 03:00:0004.08.1998
James Slaughter wrote:
>
> Forgive me for asking what must be a common question, but can someone
> provide a simplified definition of dynamic_cast, static_cast, const_cast
> and
> reintepret_cast to that found in the old public draft standard?

static_cast:
Do a conversion which may be done implicit, or the reverse of a
standard conversion
dynamic_cast:
Do a conversion inside a class hierarchy, and check for that
conversion
being valid, using RTTI. Unlike other casts, this can do downcasting
through virtual inheritance. It works only with polymorphic classes
(that is, classes having virtual member functions), but is the safest
cast of all (the result is either valid, or a NULL pointer for pointer
casts, or a bad_cast exception is thrown for reference casts)
const_cast:
Add or remove const and/or volatile (the other casts cannot do that)
reinterpret_cast:
Reinterpret the data as something different. That is, don't care
much about the meaning of the bits according to the old type,
instead interpret the raw data according to the new type.

old-style cast:
If the casting can be done with a static_cast possibly followed
by a const_cast, do so. Otherwise do a reinterpret_cast possibly
followed by a const_cast. Unlike the new casts, this can be used
to cast to a private base class; if this is not needed, old style
casts should generally be avoided because of their complex semantics.

>
> I am particularly interested in the difference between these and the
> old, C
> style casts... I've read that only the new style should be used in new

> code... not a problem, but why? When should I use which?

Generally: Use the new style casts, except if you can't.
The only thing I know which you can do with old-style casts but not
new-style casts is to cast to a private base class.

The new-style casts have the advantage that

- they allow you to express exactly what you intend with the cast,
therefore avoiding errors

Example:

Original code:

void f(int const& i)
{
// ...
system_call((int*)&i);
// system_call is not const correct, so I cast away const
// ...
}

Later the OS changed to use a typedef int syscall_t.
You adapt your code:

void f(syscall_t const& i)
{
// ...
system_call((int*)&i);
// you forgot to change this, but the error doesn't cause a problem
// since syscall_t is still int
// ...
}

Then the OS changes syscall_t to long for some reason. Since you
have rewritten your code to use syscall_t, you don't expect an error,
but your program crashes, because you reinterpret a pointer to
const long (&i) as a pointer to int (cast to int*), which turns
out to be a different size on that particular system.

If you had used a

system_call(const_cast<int*>(&i));

at the very beginning, the compiler would have complained about
the (unwanted!) type change, and therefore would have saved you
much time finding the bug.

- they allow you to easily find the casts in your program

Just do a search for "_cast", and you're there.
Since casts are often sources of trouble, it's an advantage to be
able to find them easily.

- they are quite visible

Old-style casts can easily be overlooked, since they have no
eye-catching structure. The xxx_cast<yyy> syntax jumps into your
eyes.

> How does it
> affect
> class member cast functions?, such as:
>
> class Foo {
> public:
> operator int ();
> };

This would be used by implicit conversions, static casts and
old-style casts. It would not be used by any other cast.

>
> As I understand it, the following definitions apply... please correct me
> where I'm wrong, or enlighten me as to further details:
>
> All casts return a null pointer of the specified type when they fail, or
> if
> the original argument was null, except when the specified result type is
> a
> reference, when the exception bad_cast is thrown (should I always check
> for
> this?)

Wrong. This is only true for dynamic_cast (which is something
that cannot be done with old style casts). The other casts just
prevent you from unwanted semantics, but they don't prevent
all invalid casts (for example, you can do
static_cast<Derived*>(pBase), even if pBase doesn't point to a
Derived, without getting warned - except that your program might
behave quite strange). All other casts cannot fail (they may
fail to compile, though).

>
> A const is a const is a const... :) none of the casts affect this?

The const_cast affects this (guess why the name ;-)). No other
new-style cast affects this.

>
> The cast an be treated like a function call, with regards to
> LValue/RValue
> stuff (if converted to a reference, it can be an LValue?)

I don't understand your comment about function calls correctly,
but yes, using a reference indicates that you want to have an
lvalue.

>
> 'reinterpret_cast' is for doing slightly dodgy conversions, like casting
> to
> a different type of function, or converting a char* to an int*, in order
> to
> read a DWORD (32bit). 'reinterpret_cast' is machine and implementation
> dependant, not guaranteed to be two-way, and generally equivelent to a C
> style cast.

Old-style casts are not always equivalent to a reinterpret_cast
(for example (Derived*)pBase is equivalent to
static_cast<Derived*>(pBase),
but not necessarily to reinterpret_cast<Derived*>(pBase)).

>
> 'dynamic_cast' is for taking a pointer to a base class, and casting it
> to a
> derived type. It will fail if the original value was not the specified
> type,
> or does not have a dynamic type that is, or had as a base (?), the class
> specified. Presumably it can also cast to a base type... how is multiple
> inheritance handles?

Correctly, of course ;-)

If the destination class appears as base class more than once, the cast
might be ambiguous. I don't see another problem.

>
> 'static_cast' can modify the type of an expression as well as a value?

> It
> seems to guarantee not to change the value of a pointer, but what else
> does
> it do?

Well, indeed it *does* guarantee to change the "value" of a pointer
if necessary, f.ex. to cast between base and derived, esp. in MI.
In addition, it calls conversion constructors and conversion functions
if they are available, and it converts between int, long, double, ...
The general rule is: It does an implicit conversion or the reverse of
a standard conversion.

>
> 'const_cast' confuses me even more than static_cast. Please help :)

Just adds/removes const/volatile, without changing anything else.

For example:

void f(char const* I_promise_I_wont_change_the_string)
{
// cast away the const...
char* cheater = const_cast<char*>(I_promise_I_wont_change_the_string);

// ... and play with the data
cheater[0]='\0'; // Hey, I'm evil ;-)

Paddy Spencer

не прочитано,
5 авг. 1998 г., 03:00:0005.08.1998
[The chopped lines can be avoided by setting your line-length lower. I'm
not sure about the other moderators, but 72 characters works pretty well
for me --hlh]

Kello 4 Aug 1998 13:16:36 -0400, "Paul D. DeRocco" <pder...@ix.netcom.com>
kirjoittanut:

: float ratio(int x, int y) { return float(x) / float(y); }

Does this actually cast x and y to floats or construct temporaries from
them;
come to that is there a difference between casting and constucting
temporaries?

If the class explicitly provides a cast operator, such as:

class Foo
{
float* _f;

public:
...
float* operator float*() { return _f; }
};

then yes, casting does not involve temps, but for POD's?


--
Paddy Spencer
Parallax Solutions Ltd (http://www.parallax.co.uk/)

Jerry Leichter

не прочитано,
5 авг. 1998 г., 03:00:0005.08.1998
| : float ratio(int x, int y) { return float(x) / float(y); }
|
| Does this actually cast x and y to floats or construct temporaries
| from them; come to that is there a difference between casting and
| constucting temporaries?

For a built-in type T, T(x) is simply a different notation for (T)x.

Casting in C has *always* had more complexity that most people simply
internalize without thinking about it: Some casts are actually
*conversions*, while others are simply "type puns". People that the
latter are prevalent, because in practice most *uses* of casts that
appear in programs are of the latter form; but if you instead look at
the possible "from" and "to" types, most casts are actually conversions.

In particular, (float)i (where i is an int), does *not* mean "pretend
the bit pattern of i represents a float" (which would be a "type pun");
it means "give me the float with the same numerical value as the int in
i" (a conversion). People get fooled by examples like (unsigned)-1
which *looks like* a type pun - but if you look at the actual definition
of this operation, you'll see that unsigned arithmetic is defined as
arithmetic mod 2^n, and the cast is a conversion that chooses the value
in [0,1,...,2^n-1] congruent to -1 mod 2^n. It just happens that for
2's complement arithmetic, the bit representation doesn't change.

Even casts between pointers are conversions: A char* may not be the
same size as an int* on non-byte-addressed machines, so a simple "view
the bits as another kind of pointer" won't even give the right size.
Casts between pointers of the same size typically are *implemented* by
simply leaving the bits alone, but they don't *have* to be: A checking
implementation *could* carry information about the size of the memory
allocated along with the pointer.

In fact, the only real "type puns" are casts between integral types and
pointers!

Returning to the original question: There are necessarily temporaries
created when you cast from an int to a float, since there's a real
conversion, and the result has to go *somewhere*. In practice, the
"temporary" will almost certainly live, very briefly, in a machine
register. They will certainly not be allocated from the heap. There
are no explicit constructors or destructors for a built-in type like
float, so no code executes to construct or destruct the "temporary".
So whether this is a temporary in some technicals sense or not is pretty
hard to observe....
-- Jerry

Andrew Skiba

не прочитано,
6 авг. 1998 г., 03:00:0006.08.1998

Jerry Leichter wrote in message <35C886...@smarts.com>...

>| : float ratio(int x, int y) { return float(x) / float(y); }
>|
>| Does this actually cast x and y to floats or construct temporaries
>| from them; come to that is there a difference between casting and
>| constucting temporaries?
>
>For a built-in type T, T(x) is simply a different notation for (T)x.
>
Not exactly, if you're talking about C++
try to compile these examples to see the differences:
int i=3;
unsigned u;
/* 1-st way 2-nd way */
i=(int)u;
i=int(u);

You'll see the second line will give you a message "Possible data lost in
conversion" or a like, while the first simply copies the bits. I beleive the
first is "type pun", while the second must do the conversion according to
C++ definition.

Regarding your (float) example. If you'll check the float format for most
processors, they store mantissa at least significant bits, so there is no
magic in 5.0==(float) 5

Am I wrong in something?

Pete Becker

не прочитано,
7 авг. 1998 г., 03:00:0007.08.1998
Andrew Skiba wrote:
>
> Not exactly, if you're talking about C++
> try to compile these examples to see the differences:
> int i=3;
> unsigned u;
> /* 1-st way 2-nd way */
> i=(int)u;
> i=int(u);
>
> You'll see the second line will give you a message "Possible data lost in
> conversion" or a like, while the first simply copies the bits. I beleive the
> first is "type pun", while the second must do the conversion according to
> C++ definition.

Actually, these two should do exactly the same thing, and the generated
code in both cases will be the same. You get a warning on one and not on
the other simply by accident. The warning is correct: there's a possible
loss of data. Compiler writers learned long ago that (int) says "I mean
it, don't warn me". Some, apparently, have not yet transferred this
knowledge to the other form.

--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com

Jerry Leichter

не прочитано,
7 авг. 1998 г., 03:00:0007.08.1998
| >For a built-in type T, T(x) is simply a different notation for (T)x.
| >
| Not exactly, if you're talking about C++
| try to compile these examples to see the differences:
| int i=3;
| unsigned u;
| /* 1-st way 2-nd way */
| i=(int)u;
| i=int(u);
|
| You'll see the second line will give you a message "Possible data lost
| in conversion" or a like, while the first simply copies the bits.

All that means is that your particular *compiler* choses to generate
error messages differently for the two cases. This has nothing
whatsoever to do with what the statements actually *mean* in C++: They
*mean* exactly the same thing. (Presumably, the compiler is silent for
the first case because C programmers are used to casts meaning "just do
it, don't make any noise".)

| I beleive the first is "type pun", while the second must do the
| conversion according to C++ definition.

Incorrect, even in C.

| Regarding your (float) example. If you'll check the float format for
| most processors, they store mantissa at least significant bits, so
| there is no magic in 5.0==(float) 5

If what you're trying to say is that the bit representation of 5 and 5.0
are the same on common processors, you're completely wrong. In fact, I
can't think of *any* processor, past or present, that I've ever seen
(and I've seen plenty) for which this was true. It's certainly false
for IEEE floating point numbers. (You're imagining that the exponent
will be 0 - i.e., 5 is 5 * 2^0 - and will thus be stored as all 0 bits.
This is wrong on two counts: The mantissa for all floating point
representations I've ever seen is taken to be in the range [0,1), so 5
would actually be stored as approximately .32 * 2^4; and the exponent is
stored in a biased notation, so an exponent with all zero bits
represents the smallest possible exponent (or, actually, an NaN).)



| Am I wrong in something?

Only in just about everything you said. :-)
-- Jerry

Munagala V. S. Ramanath

не прочитано,
7 авг. 1998 г., 03:00:0007.08.1998
dietma...@claas-solutions.de writes:

[... stuff deleted ...]

>- 'reinterpret_cast<>()' covers all remaining applications which could be
>done
> with the old fashioned cast. ALL conversion done with
>'reinterpret_cast<>()'
> are implementation dependent. Typical conversions are eg. between 'int*'
>and
> 'char*' or between different types of function pointers (ugh! be
>extremely
> careful with these one: it basically does not work...).

[... stuff deleted ...]

>> 'reinterpret_cast' is for doing slightly dodgy conversions, like casting
>> to
>> a different type of function, or converting a char* to an int*, in order
>> to
>> read a DWORD (32bit). 'reinterpret_cast' is machine and implementation
>> dependant, not guaranteed to be two-way, and generally equivelent to a C
>> style cast.

>C style cast can be done for things done with 'static_cast<>()', too.


>'reinterpret_cast<>()' cannot. This cast only for the stuff which really
>not safe.

There is one situation where a reinterpret_cast<>() is unavoidable
and, in my experience, safe: converting between "char *" and
"unsigned char *". I'm often in a situation where a library is
using "char *" as a generic pointer because, historically, that
was the most portable way (many early compilers did not support
"void *"). But the data is really unsigned (e.g. bitmaps), so in
my main program code it is typed as "unsigned char *". When calling
a library routine, I therefore need
"reinterpret_cast<char *>( ... )" for passing values in and
"reinterpret_cast<unsigned char *>( p )" for values returned by
the library.

I know of no machine/compiler/platform where _this_ particular use
of reinterpret_cast<>() is unsafe.

Ram

Siemel Naran

не прочитано,
7 авг. 1998 г., 03:00:0007.08.1998
>>For a built-in type T, T(x) is simply a different notation for (T)x.

>Not exactly, if you're talking about C++

On my compiler (g++ 2.7.2.3 under Linux 2.0), "(T)x" is implicit
conversion and "T(x)" is explicit conversion.

So if the constructor T::T(const X&) is explicit, then these lines
fail:
T action(const X& x) { return (T)x; } // fails
T action(const X& x) { return x; } // also fails, of course

If the constructor T::T(const X&) is not explicit, then the above lines
work.

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

Steve Clamage

не прочитано,
7 авг. 1998 г., 03:00:0007.08.1998
In article 1...@news.inter.net.il, "Andrew Skiba" <sk...@macs.biu.ac.il>
writes:

>
>Jerry Leichter wrote in message <35C886...@smarts.com>...
>>| : float ratio(int x, int y) { return float(x) / float(y); }
>>|
>>| Does this actually cast x and y to floats or construct temporaries
>>| from them; come to that is there a difference between casting and
>>| constucting temporaries?
>>
>>For a built-in type T, T(x) is simply a different notation for (T)x.
>>
>Not exactly, if you're talking about C++
>try to compile these examples to see the differences:
>int i=3;
>unsigned u;
>/* 1-st way 2-nd way */
> i=(int)u;
> i=int(u);
>
>You'll see the second line will give you a message "Possible data lost in
>conversion" or a like, while the first simply copies the bits. I beleive the

>first is "type pun", while the second must do the conversion according to
>C++ definition.

It may be that you compiler produces different messages for those
two examples, but Leichter is correct. The two notations are
exactly equivalent according to the language definition. See 5.2.3
and 5.4 in the draft standard. Each section references the other
and says the two forms are equivalent.

>
>Regarding your (float) example. If you'll check the float format for most
>processors, they store mantissa at least significant bits, so there is no
>magic in 5.0==(float) 5

I don't know what you are trying to say here, but it is not possible
for int and float to use the same format. The integer types are
required to use pure binary format, and such a format will not
be suitable for floating-point values. When you cast betweeen integer
and floating-point values, a temporary object of the new type must
be created someplace.

---
Steve Clamage, stephen...@sun.com

Christopher Eltschka

не прочитано,
7 авг. 1998 г., 03:00:0007.08.1998
Paul Grealish wrote:

[...]

> The exception, where a C style cast should be used, is when the
> result of a function is being 'thrown away'. In this case, use
> of the C++ equivalent static_cast tends to obfuscate the code.

[...]

> (void)sHello.size(); // Throw away function return

You don't need to cast to void. The following will work as well:

sHello.size(); // Throw away function return

[...]

jka...@otelo.ibmmail.com

не прочитано,
7 авг. 1998 г., 03:00:0007.08.1998
In article <6qc288$2dn$1...@news.inter.net.il>,

"Andrew Skiba" <sk...@macs.biu.ac.il> wrote:
>
> Jerry Leichter wrote in message <35C886...@smarts.com>...
> >| : float ratio(int x, int y) { return float(x) / float(y); }
> >|
> >| Does this actually cast x and y to floats or construct temporaries
> >| from them; come to that is there a difference between casting and
> >| constucting temporaries?
> >
> >For a built-in type T, T(x) is simply a different notation for (T)x.
> >
> Not exactly, if you're talking about C++
> try to compile these examples to see the differences:
> int i=3;
> unsigned u;
> /* 1-st way 2-nd way */
> i=(int)u;
> i=int(u);
>
> You'll see the second line will give you a message "Possible data lost in
> conversion" or a like, while the first simply copies the bits. I beleive the
> first is "type pun", while the second must do the conversion according to
> C++ definition.
>
> Regarding your (float) example. If you'll check the float format for most
> processors, they store mantissa at least significant bits, so there is no
> magic in 5.0==(float) 5
>
> Am I wrong in something?

And how. According to the standard, the only difference between T(v) and
(T)v is that in the first, T must be a simple type name, and v can in fact
contain 0 to n parameters, whereas in the second, T can be a complex type
expression, but v must be a single, simple value. The semantics when both
are legal are exactly the same, and depend on the types involved:
static_cast if legal, otherwise reinterpret_cast, either possibly followed
by const_cast. Since static_cast is legal for casting between int and
unsigned (or int and float), these are static_cast's, i.e. conversions
in the full sense of the word.

And I've never seen a floating point representation in which 5.0 would
contain the integral value 5 in the least significant bits. All of the
floating point formats I'm familiar with use a normalized representation
in which the mantissa is shifted as far left as possible; most of those
using binary representation won't bother to keep the high order bit, either,
since in the normalized representation.

--
James Kanze +33 (0)1 39 23 84 71 mailto: ka...@gabi-soft.fr
+49 (0)69 66 45 33 10 mailto: jka...@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orientée objet --
-- Beratung in objektorientierter Datenverarbeitung

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Nathan Myers

не прочитано,
8 авг. 1998 г., 03:00:0008.08.1998
Siemel Naran<sbn...@KILL.uiuc.edu> wrote:
>On my compiler (g++ 2.7.2.3), "(T)x" is implicit conversion and
>"T(x)" is explicit conversion. So if the constructor T::T(const X&)
>is explicit, then this line fails:
>
> T action(const X& x) { return (T)x; } // fails

This is a compiler bug, fixed in Egcs. It was never specified
this way in any version of the Draft.

I recommend switching from Gcc to Egcs immediately.
Egcs fixes many, many bugs.

--
Nathan Myers
n...@nospam.cantrip.org http://www.cantrip.org/

Paul D. DeRocco

не прочитано,
9 авг. 1998 г., 03:00:0009.08.1998
Munagala V. S. Ramanath wrote:
>
> There is one situation where a reinterpret_cast<>() is unavoidable
> and, in my experience, safe: converting between "char *" and
> "unsigned char *".

> I know of no machine/compiler/platform where _this_ particular use


> of reinterpret_cast<>() is unsafe.

It's so unequivocally safe that I prefer using a C-style cast in this
situation. It's less wordy, and since nothing "funny" is going on, it
isn't important that it be highly visible to a reader (or to grep).

--

Ciao,
Paul

Paul Grealish

не прочитано,
10 авг. 1998 г., 03:00:0010.08.1998
Christopher Eltschka wrote:
>
> Paul Grealish wrote:
>
> [...]
>
> > The exception, where a C style cast should be used, is when the
> > result of a function is being 'thrown away'. In this case, use
> > of the C++ equivalent static_cast tends to obfuscate the code.
>
> [...]
>
> > (void)sHello.size(); // Throw away function return
>
> You don't need to cast to void. The following will work as well:
>
> sHello.size(); // Throw away function return

Yes, I realise that - it's not a legality issue.
Our Company standard dictates that where a function
return value is ignored, that action should be
made explicit. This rule comes from the old C days
of using lint which would elicit a message about
'function return ignored' or somesuch.
But let's not get onto the subject of coding
standards :-)

--
+---------------------------------+
| Paul Grealish |
| GEOPAK-TMS Limited |
| Cambridge, England |
| paul.g...@uk.geopak-tms.com |
+---------------------------------+

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Paul D. DeRocco

не прочитано,
11 авг. 1998 г., 03:00:0011.08.1998
Paul Grealish wrote:
>
> Yes, I realise that - it's not a legality issue.
> Our Company standard dictates that where a function
> return value is ignored, that action should be
> made explicit. This rule comes from the old C days
> of using lint which would elicit a message about
> 'function return ignored' or somesuch.
> But let's not get onto the subject of coding
> standards :-)

Gee, isn't the fact that the function call stands by itself on a line
with a semicolon after it explicit enough?

--

Ciao,
Paul

Patrick de Gale

не прочитано,
11 авг. 1998 г., 03:00:0011.08.1998
I am using Borland C++ Builder.

I am trying to make a map available in multiple compilation units:

the .h file:

typedef map<AnsiString, someData, less<AnsiString> > NodeMap;
Myclass :
{
NodeMap *FieldMap;

void putMap(NodeMap* map) (FieldMap = map;};
NodeMap *getMap(void) {return FieldMap;};
};

typical .c file:

fMap = new FieldMap; // this is then populated
thisMapObject->putMap(fMap);

another .c file:

NodeMap *gMap;
gmap = thisMapObject->getfMap();
gMap->insert( ... );

The compiler complains, effectively, that no map* = map* operator is
defined.
map.h shows only a operator= for maps, not pointers.

I thought I might do it via a reinterpret_cast, which Larry Brasfield's
recent dissertation on casts suggests does no adjustment or check at
compile
or run time. This does not seem to be so, as the compiler continues to
insist no = operator can be found. It seems always to look at the
history
of the pointer, as even passing it through a void* variable did not
help.

Any help would be most gratefully received.


--
Patrick de Gale

Paul Grealish

не прочитано,
11 авг. 1998 г., 03:00:0011.08.1998
Paul D. DeRocco wrote:
>
> Paul Grealish wrote:
> >
> > Yes, I realise that - it's not a legality issue.
> > Our Company standard dictates that where a function
> > return value is ignored, that action should be
> > made explicit. This rule comes from the old C days
> > of using lint which would elicit a message about
> > 'function return ignored' or somesuch.
> > But let's not get onto the subject of coding
> > standards :-)
>
> Gee, isn't the fact that the function call stands by itself on a line
> with a semicolon after it explicit enough?

No, that's exactly the point. The reader of the
code cannot distinguish between the two cases of
a) function returning void
b) function returning something but return value
is not of interest in the current conext.

To illustrate:

extern void func1(void);
extern int func2(void);
...
func1();
func2();

As a maintainer of the above code, I'd much rather
see:
func1();
(void)func2();

It tells me that func2() returns something that
may be useful in some contexts. Maybe I'm
amending the code - that return value might
now be of interest to me.
That old lint warning wasn't there for nothing
you know :-)

--
+---------------------------------+
| Paul Grealish |
| GEOPAK-TMS Limited |
| Cambridge, England |
| paul.g...@uk.geopak-tms.com |
+---------------------------------+

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Alberto Barbati

не прочитано,
12 авг. 1998 г., 03:00:0012.08.1998

>The compiler complains, effectively, that no map* = map* operator is
>defined.
>map.h shows only a operator= for maps, not pointers.

Could you please state the exact error message emitted by your compiler?
You
see... there no need (and no way, in c++) to define a copy operator for
pointers. They're just pointers to the same type, the copy operator is
always defined in this case: it just gets a copy of the address.

>I thought I might do it via a reinterpret_cast, which Larry Brasfield's
>recent dissertation on casts suggests does no adjustment or check at
>compile
>or run time. This does not seem to be so, as the compiler continues to
>insist no = operator can be found. It seems always to look at the
>history
>of the pointer, as even passing it through a void* variable did not
>help.

If you are thinking about using the reinterpret_cast in that case, then,
IMHO, you should read again Larry Brasfield's dissertation... The
reinterpret_cast as a very specific and narrow use, and this it not the
case.
Furthermore, a pointer has no "history": if you cast it to void* and the
program does not compile... then the problem is surely elsewhere.

Hope this help.

--
Alberto Barbati
alb...@tin.it

Gerhard Menzl

не прочитано,
12 авг. 1998 г., 03:00:0012.08.1998
Patrick de Gale wrote:

> I am using Borland C++ Builder.
>
> I am trying to make a map available in multiple compilation units:
>
> the .h file:
>
> typedef map<AnsiString, someData, less<AnsiString> > NodeMap;
> Myclass :
> {
> NodeMap *FieldMap;
>
> void putMap(NodeMap* map) (FieldMap = map;};
> NodeMap *getMap(void) {return FieldMap;};
> };
>
> typical .c file:
>
> fMap = new FieldMap; // this is then populated
> thisMapObject->putMap(fMap);

Is this a typo or actual code? FieldMap is a variable in your example,
not
a type; therefore you cannot create a new FieldMap. You should get a
syntax
error on this. I guess that what you meant is:

fMap = new NodeMap;

> another .c file:
>
> NodeMap *gMap;
> gmap = thisMapObject->getfMap();
> gMap->insert( ... );
>

> The compiler complains, effectively, that no map* = map* operator is
> defined.
> map.h shows only a operator= for maps, not pointers.
>

> I thought I might do it via a reinterpret_cast, which Larry Brasfield's
> recent dissertation on casts suggests does no adjustment or check at
> compile
> or run time. This does not seem to be so, as the compiler continues to
> insist no = operator can be found. It seems always to look at the
> history
> of the pointer, as even passing it through a void* variable did not help.

What is the exact error message you get, and which is the offending
line?
Pointers are not class objects, thus you cannot overload operator= for
them, just as you cannot overload operator= for int or char. Assignment
for
pointers is always done via the built-in assignment operator. As long as
both the lvalue and the rvalue point to the same type, no cast is
necessary.

Gerhard Menzl

Mark Wilden

не прочитано,
13 авг. 1998 г., 03:00:0013.08.1998
Paul Grealish wrote in message <35D02F...@uk.geopak-tms.com>...

>
> extern void func1(void);
> extern int func2(void);
> ...
> func1();
> func2();
>
>As a maintainer of the above code, I'd much rather
>see:
> func1();
> (void)func2();
>
>It tells me that func2() returns something that
>may be useful in some contexts.

Does that coding standard also require this?

void func(int a = 1, int b = 2);
//...
func(/*int a = 1, int b = 2*/);

It seems to me the situations are analogous, and neither is
particularly useful. I mean, you could also put in a comment above
each call specifying exactly what each function takes as parameters,
what it returns, and what it's supposed to do. That would certainly
help maintenance (assuming these things didn't change). But at some
point, I think you have to rely on maintainers to simply look at a
header file.

Paul D. DeRocco

не прочитано,
13 авг. 1998 г., 03:00:0013.08.1998
Paul Grealish wrote:

>
> Paul D. DeRocco wrote:
> >
> > Gee, isn't the fact that the function call stands by itself on a
> > line with a semicolon after it explicit enough?
>
> No, that's exactly the point. The reader of the
> code cannot distinguish between the two cases of
> a) function returning void
> b) function returning something but return value
> is not of interest in the current conext.
>
> To illustrate:
>
> extern void func1(void);
> extern int func2(void);
> ...
> func1();
> func2();
>
> As a maintainer of the above code, I'd much rather
> see:
> func1();
> (void)func2();
>
> It tells me that func2() returns something that
> may be useful in some contexts. Maybe I'm
> amending the code - that return value might
> now be of interest to me.

Gee, I feel exactly the opposite. If the returned value is being
ignored, I don't want to know about it. Your rationale would also
prohibit reliance on default parameter values, I would think.

Besides, the (void) merely tells you that _something_ is returned,
without telling you what, or even what type. So it's only incomplete
info anyway.

I used to write PL/M-86 code, which required that every return value be
used. This meant declaring junk variables to put them it, which was an
even worse irritation.

--

Ciao,
Paul

Mitch

не прочитано,
13 авг. 1998 г., 03:00:0013.08.1998
This is a perfect example of a ridiculous company enforced programming
standard. Good standards contribute to the production of quality code.
This
one does not fall into that category. Generally, rules about syntax are
not
as productive as rules about semantics.( As an example, a rule enforcing
underscore naming convention versus first capitals would not acheive as
much as a rule regarding the semantics of variable naming such as "use
common nouns for classes and proper nouns for objects etc...)

If any function returns a value, and the coder does not care about its
value, then the stand alone function call is more than sufficient. If,
on
the other hand the coder should have been checking the return value,
then
consulting the design should highlight this.

Perhaps a better company standard would be "check all return values". Or
do
you think that might be taking things to far?

Mitch

Paul Grealish <paul.g...@uk.geopak-tms.com> wrote in article
<35D02F...@uk.geopak-tms.com>...
> Paul D. DeRocco wrote:

<snip>

>
> No, that's exactly the point. The reader of the
> code cannot distinguish between the two cases of
> a) function returning void
> b) function returning something but return value
> is not of interest in the current conext.
>
> To illustrate:
>
> extern void func1(void);
> extern int func2(void);
> ...
> func1();
> func2();
>
> As a maintainer of the above code, I'd much rather
> see:
> func1();
> (void)func2();
>
> It tells me that func2() returns something that
> may be useful in some contexts. Maybe I'm
> amending the code - that return value might
> now be of interest to me.

> That old lint warning wasn't there for nothing
> you know :-)
>

Doug Harrison

не прочитано,
14 авг. 1998 г., 03:00:0014.08.1998
On 13 Aug 1998 16:01:35 -0400, "Mark Wilden" <Ma...@mWilden.com> wrote:

>Does that coding standard also require this?
>
>void func(int a = 1, int b = 2);
>//...
>func(/*int a = 1, int b = 2*/);

Excellent point!

>It seems to me the situations are analogous, and neither is
>particularly useful. I mean, you could also put in a comment above
>each call specifying exactly what each function takes as parameters,
>what it returns, and what it's supposed to do. That would certainly
>help maintenance (assuming these things didn't change). But at some
>point, I think you have to rely on maintainers to simply look at a
>header file.

Or other documentation. It seems to me that's a prerequisite for
knowing what you're doing, which I hope is considered important even
for maintainers. This sort of "call-site clue" is often used to
justify using pointer parameters to indicate a function may modify one
of its arguments, so that you have to say fun(&x) instead of fun(x).
Well, if x is a pointer, you will call it as fun(x), and the call-site
clue reveals how unreliable it really is. I prefer non-const
references for this. I use pointer parameters to indicate a change of
ownership, to allow null pointers, and when I have to, such as when
providing an interface for arrays.

--
Doug Harrison
dHar...@worldnet.att.net

Mark Wilden

не прочитано,
15 авг. 1998 г., 03:00:0015.08.1998
Paul D. DeRocco wrote in message <35D240FD...@ix.netcom.com>...
>> (void)func2();

>
>Besides, the (void) merely tells you that _something_ is returned,
>without telling you what, or even what type. So it's only incomplete
>info anyway.

Furthermore, this is one of those "compiled comments" that looks like
it uses the language to say something about the function, but doesn't
actually. If func2() is later changed to actually return void, this
line will still compile aziz, but will be misleading to those who rely
on this style.

Ответить всем
Написать сообщение автору
Переслать
0 новых сообщений