449,423 Members | 1,294 Online
Need help? Post your question and get tips & solutions from a community of 449,423 IT Pros & Developers. It's quick & easy.

casting A* to A& ?

 P: n/a What happens exactly when I do the following: struct A { int i; string j; A() {} }; void f(A& a) { cout << a.i << endl; } int _tmain(int argc, _TCHAR* argv[]) { A a; a.i = 6; A* pa = &a; f((A&)pa); // CRITICAL POINT f(*pa); // works as expected return 0; } How come that this is legal, anyway? Lately I've seen some people expect that (A&)pa be equivalent to *pa, which is not according to the example above. (The output for f((A&)pa) looks like some integer, but surely not 6 as should be if it meant f(*pa).) Nov 17 '05 #1
44 Replies

 P: n/a Agoston Bejo wrote: What happens exactly when I do the following: struct A { int i; string j; A() {} }; void f(A& a) { cout << a.i << endl; } int _tmain(int argc, _TCHAR* argv[]) { A a; a.i = 6; A* pa = &a; f((A&)pa); // CRITICAL POINT f(*pa); // works as expected return 0; } How come that this is legal, anyway? You can cast something at an address to something else at the same address. Try doing the same cast with a constant and you'll see that that is not allowed. Lately I've seen some people expect that (A&)pa be equivalent to *pa, which is not according to the example above. No, it is not. *pa is a reference to whatever pa is pointing to, tho. So f(*pa); is perfectly fine. (The output for f((A&)pa) looks like some integer, but surely not 6 as should be if it meant f(*pa).) The integer is equal to the address of a. What actually happens is you're telling the compiler that "look here, pa is not a pointer it's a struct of type A". That is in fact wrong, but because you're telling the compiler that you know better it let's you do it. And you're lucky, because the size of pa happens to be the same as the size of an A instance. As it happens, the value of p overlaps A::i when you do the cast. Thus, you only get bogus results in this simple example, in reality you'd usually get an access violation or some other hardtofind bug. In other words, when you use a typecast, you're telling the compiler that you know what you're doing. And that's a very silly thing to tell the compiler if you don't know what you're doing... (Yes, references are implemented the same way as pointers. But they have different semantics.) -- Sigurd http://utvikling.com Nov 17 '05 #2

 P: n/a Thanks for the thorough answer! "Sigurd Stenersen" wrote in message news:%2******************@TK2MSFTNGP15.phx.gbl... [...] What actually happens is you're telling the compiler that "look here, pa is not a pointer it's a struct of type A". That is in fact wrong, but because you're telling the compiler that you know better it let's you do it. And So does (Type)var mean the same as reinterpret_cast(var)? I thought it meant static_cast(var). Or is it context-dependent, how C-style casts are interpreted? you're lucky, because the size of pa happens to be the same as the size of an A instance. As it happens, the value of p overlaps A::i when you do the cast. I think the first statement (about the sizes) is not really relevant, what matters is that the size of an A instance is at least as big as the size of pa, so no out-of-heap memory is read which could cause access violation. Am I right? However, I've tried it with A having only a char member and nothing else, but no access violation occured in this case, either. (I compiled the example both in debug and release mode.) I think it should have produced some runtime error, especially in debug mode, shouldn't it? Nov 17 '05 #3

 P: n/a Hello, What happens exactly when I do the following: struct A { int i; string j; A() {} }; void f(A& a) { cout << a.i << endl; } int _tmain(int argc, _TCHAR* argv[]) { A a; a.i = 6; A* pa = &a; f((A&)pa); // CRITICAL POINT f(*pa); // works as expected return 0; } How come that this is legal, anyway? Lately I've seen some people expect that (A&)pa be equivalent to *pa, which is not according to the example above. (The output for f((A&)pa) looks like some integer, but surely not 6 as should be if it meant f(*pa).) If you would used C++ style cast notation. The only valid code would be: f(reinterpret_cast(pa)); // A* & -> A &. When you see *_cast operators in code, this often means that program could be written better. But when you see reinterpret_cast, this usually means that something is wrong, unless it's low level code. -- Vladimir Nesterovsky e-mail: vl******@nesterovsky-bros.com home: http://www.nesterovsky-bros.com Nov 17 '05 #4

 P: n/a Agoston Bejo wrote: "Sigurd Stenersen" wrote in message news:%2******************@TK2MSFTNGP15.phx.gbl... [...] What actually happens is you're telling the compiler that "look here, pa is not a pointer it's a struct of type A". That is in fact wrong, but because you're telling the compiler that you know better it let's you do it. And So does (Type)var mean the same as reinterpret_cast(var)? I *think* so. I don't use that sort of cast myself. Or is it context-dependent, how C-style casts are interpreted? No. you're lucky, because the size of pa happens to be the same as the size of an A instance. As it happens, the value of p overlaps A::i when you do the cast. I think the first statement (about the sizes) is not really relevant, Oh, yes, it is *highly* relevant. Consider this : struct A { // char s[100000]; int i; }; void f(A& a) { cout << a.i << endl; } void main() { A *pa = new A; f((A&) pa); } That will be bogus but still "work". Now, remove the // from the third line and guess what happens ? Also, consider your original code and just change the cout statement to cout << a.i << a.j.c_str() << endl; and you achieve pretty much the same result... what matters is that the size of an A instance is at least as big as the size of pa, so no out-of-heap memory is read which could cause access violation. Am I right? No, it's the other way around. As long as the variable that's actually used (pa) is big enough, at least you wont corrupt other variables. Still, the results will be bogus at best. However, I've tried it with A having only a char member and nothing else, but no access violation occured in this case, either. (I compiled the example both in debug and release mode.) I think it should have produced some runtime error, especially in debug mode, shouldn't it? No, it's *legal*. You told the compiler you knew what you were doing... -- Sigurd http://utvikling.com Nov 17 '05 #5

 P: n/a On Fri, 8 Oct 2004 14:27:40 +0200, "Agoston Bejo" wrote: Thanks for the thorough answer! "Sigurd Stenersen" wrote in messagenews:%2******************@TK2MSFTNGP15.phx.gbl. ..[...] What actually happens is you're telling the compiler that "look here, pais not a pointer it's a struct of type A". That is in fact wrong, butbecause you're telling the compiler that you know better it let's you do it. AndSo does (Type)var mean the same as reinterpret_cast(var)?I thought it meant static_cast(var).Or is it context-dependent, how C-style casts are interpreted? It is context dependent. A C-style cast can act as a static_cast, a const_cast or a reinterpret_cast, as well as combinations of those. It can also perform casts that can't even be done by reinterpret_cast, such as casting to a private base class. you're lucky, because the size of pa happens to be the same as the size of an A instance. As it happens, the value of p overlaps A::i when you dothe cast.I think the first statement (about the sizes) is not really relevant, whatmatters is that the size of an A instance is at least as big as the size ofpa, so no out-of-heap memory is read which could cause access violation. AmI right? The important thing is that your function f only accesses the first 4 bytes of the passed object, so it only accesses the 4 bytes of the passed pointer value, giving out a garbage int value that is the value of the passed pointer. However, the code has undefined behaviour. However, I've tried it with A having only a char member and nothing else,but no access violation occured in this case, either. (I compiled theexample both in debug and release mode.) Try instead changing your function to print out a.j rather than a.i. That will likely cause a proper crash, since it will treat the bytes of stack space after the passed pointer as a valid string object, when in reality they probably contain random byte values. I think it should have produced some runtime error, especially in debugmode, shouldn't it? Undefined behaviour often doesn't produce any obvious results, rather it corrupts the heap or stack, causing your program to produce incorrect results or crash further down the line. It you're very lucky it crashes at the point of the error, but this is quite rare. Tom Nov 17 '05 #6

 P: n/a C-style cast are interpreted either as static_cast (if a standard conversion exists), or reinterpret_cast otherwise. "Sigurd Stenersen" wrote in message news:OQ**************@TK2MSFTNGP12.phx.gbl... So does (Type)var mean the same as reinterpret_cast(var)? I *think* so. I don't use that sort of cast myself. Or is it context-dependent, how C-style casts are interpreted? No. you're lucky, because the size of pa happens to be the same as the size of an A instance. As it happens, the value of p overlaps A::i when you do the cast. I think the first statement (about the sizes) is not really relevant, Oh, yes, it is *highly* relevant. Consider this : struct A { // char s[100000]; int i; }; void f(A& a) { cout << a.i << endl; } void main() { A *pa = new A; f((A&) pa); } That will be bogus but still "work". Now, remove the // from the third line and guess what happens ? Also, consider your original code and just change the cout statement to cout << a.i << a.j.c_str() << endl; and you achieve pretty much the same result... what matters is that the size of an A instance is at least as big as the size of pa, so no out-of-heap memory is read which could cause access violation. Am I right? No, it's the other way around. As long as the variable that's actually used (pa) is big enough, at least you wont corrupt other variables. Still, the results will be bogus at best. However, I've tried it with A having only a char member and nothing else, but no access violation occured in this case, either. (I compiled the example both in debug and release mode.) I think it should have produced some runtime error, especially in debug mode, shouldn't it? No, it's *legal*. You told the compiler you knew what you were doing... -- Sigurd http://utvikling.com Nov 17 '05 #7

 P: n/a Tom Widmer wrote: On Fri, 8 Oct 2004 14:27:40 +0200, "Agoston Bejo" wrote: Thanks for the thorough answer! "Sigurd Stenersen" wrote in message news:%2******************@TK2MSFTNGP15.phx.gbl... [...] What actually happens is you're telling the compiler that "look here, pa is not a pointer it's a struct of type A". That is in fact wrong, but because you're telling the compiler that you know better it let's you do it. And So does (Type)var mean the same as reinterpret_cast(var)? I thought it meant static_cast(var). Or is it context-dependent, how C-style casts are interpreted? It is context dependent. A C-style cast can act as a static_cast, a const_cast or a reinterpret_cast, as well as combinations of those. It can also perform casts that can't even be done by reinterpret_cast, such as casting to a private base class. It does the same thing no matter what the context is - it treats something of one type like it actually is some other type. Casting to certain types results in the creation of a temporary object of the destination type. However, that's not related to context but rather it's related to the destination type. -- Sigurd http://utvikling.com Nov 17 '05 #8

 P: n/a Alexander Grigoriev wrote: "Sigurd Stenersen" wrote in message Or is it context-dependent, how C-style casts are interpreted? No. C-style cast are interpreted either as static_cast (if a standard conversion exists), or reinterpret_cast otherwise. So ? C-style casts work the same way in any context. You could argue that there is one exception (I mentioned this in my last post), but that's depending on the target type rather than on the context and it's not really a cast anyway. It just looks like one. -- Sigurd http://utvikling.com Nov 17 '05 #9

 P: n/a Sigurd Stenersen wrote: Tom Widmer wrote: It is context dependent. A C-style cast can act as a static_cast, a const_cast or a reinterpret_cast, as well as combinations of those. It can also perform casts that can't even be done by reinterpret_cast, such as casting to a private base class. It does the same thing no matter what the context is - it treats something of one type like it actually is some other type. Tom is correct. According to 5.4/5 and 5.4/7 of the C++ Standard: 5 The conversions performed by - a const_cast (5.2.11), - a static_cast (5.2.9), - a static_cast followed by a const_cast, - a reinterpret_cast (5.2.10), or - a reinterpret_cast followed by a const_cast, can be performed using the cast notation of explicit type conversion. The same semantic restrictions and behaviors apply. If a conversion can be interpreted in more than one of the ways listed above, the interpretation that appears first in the list is used, even if a cast resulting from that interpretation is illformed. If a conversion can be interpreted in more than one way as a static_cast followed by a const_cast, the conversion is illformed. [Example: struct A {}; struct I1 : A {}; struct I2 : A {}; struct D : I1, I2 {}; A *foo( D *p ) { return (A*)( p ); // illformed static_cast interpretation } -end example] 7 In addition to those conversions, the following static_cast and reinterpret_cast operations (optionally followed by a const_cast operation) may be performed using the cast notation or explicit type conversion, even if the base class type is not accessible: - a pointer to an object of derived class type or an lvalue of derived class type may be explicitly converted to a pointer or reference to an unambiguous base class type, respectively; - a pointer to member of derived class type may be explicitly converted to a pointer to member of an unambiguous nonvirtual base class type; - a pointer to an object of nonvirtual base class type, an lvalue of nonvirtual base class type, or a pointer to member of nonvirtual base class type may be explicitly converted to a pointer, a reference, or a pointer to member of a derived class type, respectively. -cd Nov 17 '05 #10

 P: n/a "Sigurd Stenersen" wrote in message news:%2****************@TK2MSFTNGP15.phx.gbl... Alexander Grigoriev wrote: "Sigurd Stenersen" wrote in message Or is it context-dependent, how C-style casts are interpreted? No. C-style cast are interpreted either as static_cast (if a standard conversion exists), or reinterpret_cast otherwise. So ? C-style casts work the same way in any context. You could argue that there is one exception (I mentioned this in my last post), but that's depending on the target type rather than on the context and it's not really a cast anyway. It just looks like one. You've made a distinction I cannot follow, and I believe it is incorrect as well. The 'target type' certainly must be considered part of the context of an expression forming the right-hand side of an assignment. The very reason that the old C casts should be avoided is because they can do different things depending on context. For example, consider this cast: x_ptr = (SomeType *)p; Is is a static_cast or a reinterpret_cast? You cannot tell until we know the types of both x_ptr and p. Given these declarations: class Base {} *p; class Derv : public Base {} *x_ptr; then it was a static_cast. Given these declarations: class Apple {} *p; class Orange {} *x_ptr; then it was a reinterpret_cast. What makes the C cast so insidious is that its operation can change as a side effect of changes in code far removed from the location of the cast. If not for that misfeature, (if they were as stable as you claim), they would be safer to use. A static_cast would always remain a converstion between compatible types, (and a reinterpret_cast would remain as dangerous as ever). Sigurd http://utvikling.com -- --Larry Brasfield email: do***********************@hotmail.com Above views may belong only to me. Nov 17 '05 #11

 P: n/a Carl Daniel [VC++ MVP] wrote: Sigurd Stenersen wrote: Tom Widmer wrote: It is context dependent. A C-style cast can act as a static_cast, a const_cast or a reinterpret_cast, as well as combinations of those. It can also perform casts that can't even be done by reinterpret_cast, such as casting to a private base class. It does the same thing no matter what the context is - it treats something of one type like it actually is some other type. Tom is correct. I didn't say he's wrong. I pointed out that the C-style cast does the same thing no matter what you use it for. The fact that you have three different ways to do a C++ style cast, with different restrictions for each one, does not change the way the C-style cast works... -- Sigurd http://utvikling.com Nov 17 '05 #12

 P: n/a Larry Brasfield wrote: "Sigurd Stenersen" wrote in message news:%2****************@TK2MSFTNGP15.phx.gbl... Alexander Grigoriev wrote: "Sigurd Stenersen" wrote in message> Or is it context-dependent, how C-style casts are interpreted? No. C-style cast are interpreted either as static_cast (if a standard conversion exists), or reinterpret_cast otherwise. So ? C-style casts work the same way in any context. You could argue that there is one exception (I mentioned this in my last post), but that's depending on the target type rather than on the context and it's not really a cast anyway. It just looks like one. You've made a distinction I cannot follow, and I believe it is incorrect as well. It's not *that* hard... Given char *p = "..."; (std::string) p; you're doing something more than just changing the "compiler perceived" type. My point is that this is not really a cast, it's an instantiation exactly the same way that char *p = "..."; std::string(p); is an instantiation and not a cast. The case is not the same for actual typecasts that use the same notation, e.g. int i; (char) i; is the same as int i; char(i); which is a cast and not an instantiation. The 'target type' certainly must be considered part of the context of an expression forming the right-hand side of an assignment. In that case we have different ideas about the meaning of the word "context". I guess I could be wrong, english is not my native language. -- Sigurd http://utvikling.com Nov 17 '05 #13

 P: n/a On Fri, 8 Oct 2004 16:20:27 +0200, "Sigurd Stenersen" wrote: Tom Widmer wrote: On Fri, 8 Oct 2004 14:27:40 +0200, "Agoston Bejo" wrote: Thanks for the thorough answer! "Sigurd Stenersen" wrote in message news:%2******************@TK2MSFTNGP15.phx.gbl... [...] What actually happens is you're telling the compiler that "look here, pa is not a pointer it's a struct of type A". That is in fact wrong, but because you're telling the compiler that you know better it let's you do it. And So does (Type)var mean the same as reinterpret_cast(var)? I thought it meant static_cast(var). Or is it context-dependent, how C-style casts are interpreted? It is context dependent. A C-style cast can act as a static_cast, a const_cast or a reinterpret_cast, as well as combinations of those. It can also perform casts that can't even be done by reinterpret_cast, such as casting to a private base class.It does the same thing no matter what the context is - it treats somethingof one type like it actually is some other type. By context I mean the combination of source type and destination type. Without knowing both of those types, you can't tell what conversion is going to be performed. Depending on the relationship, the cast might cause a function to be called, might need a cast pointer value to be adjusted (multiple inheritence), or it might not need to do anything at runtime. const_cast, static_cast and reinterpret_cast give you more control, since each of them will only do a subset of what a C-style cast can do. Casting to certain types results in the creation of a temporary object ofthe destination type. All casts to non-reference types give you a temporary (or rvalue), unless I'm mistaken. However, that's not related to context but ratherit's related to the destination type. The point is that what the cast dose is related to both source and destination type, and the relationship between those types. Tom Nov 17 '05 #14

 P: n/a "Sigurd Stenersen" wrote in message news:ue**************@TK2MSFTNGP15.phx.gbl Tom Widmer wrote: It is context dependent. A C-style cast can act as a static_cast, a const_cast or a reinterpret_cast, as well as combinations of those. It can also perform casts that can't even be done by reinterpret_cast, such as casting to a private base class. It does the same thing no matter what the context is - it treats something of one type like it actually is some other type. You seem to argue that a C-style cast is always the same as reinterpret_cast - that is, it just takes bits in memory, and interprets these bits as a representation of a different type. This is not always so. Consider: class A {int a;}; class B {int b;}; class C : public A, public B {}; C c; C* pC = &c; B* pB1 = static_cast(pC); Here, the physical value of pB1 is very likely different from that of pC (that is, (void*)pB1 != (void*)pC ), because B subobject is at a non-zero offset inside C (a zero offset is most likely occupied by A subobject). B* pB2 = reinterpret_cast(pC); Here, the physical value of pB2 is the same as pC (that's the whole point of reinterpret_cast). Incidentally, pB2 does not point to a valid object of type B. Dereferencing it would cause undefined behavior. B* pB3 = (B*)pC; Here, the C-style cast behaves the same way as static_cast, not as reinterpret_cast. pB3 == pB1 and is different from pC. class D {}; D* pD = (D*)pC; Here, C-style cast behaves like reinterpret_cast - the physical value of pD is the same as pC. That's what people mean when they say C-style cast is context-sensitive - it behaves differently when casting between related types than when casting between unrelated ones; it takes the relation between the two types into account. Contrast this with reinterpret_cast, which just blindly takes the bit layout as is, and treats it as a different type. -- With best wishes, Igor Tandetnik "On two occasions, I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able to rightly apprehend the kind of confusion of ideas that could provoke such a question." -- Charles Babbage Nov 17 '05 #15

 P: n/a On Fri, 8 Oct 2004 15:32:29 +0200, "Sigurd Stenersen" wrote: However, I've tried it with A having only a char member and nothing else, but no access violation occured in this case, either. (I compiled the example both in debug and release mode.) I think it should have produced some runtime error, especially in debug mode, shouldn't it?No, it's *legal*. You told the compiler you knew what you were doing... To put it more precisely, the code is well-formed but exhibits undefined behaviour. Tom Nov 17 '05 #16

 P: n/a "Agoston Bejo" wrote in message news:eY***************@TK2MSFTNGP09.phx.gbl int _tmain(int argc, _TCHAR* argv[]) { A a; a.i = 6; A* pa = &a; f((A&)pa); // CRITICAL POINT This is undefined behavior, so there are no rules on how the compiler should interpret it. I believe VC++ would treat it the same way as f( *(A*)&pa ); That is, the memory occupied by pa pointer is treated as if it held A object. Inside f, a.i would likely be equal to (int)pa -- With best wishes, Igor Tandetnik "On two occasions, I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able to rightly apprehend the kind of confusion of ideas that could provoke such a question." -- Charles Babbage Nov 17 '05 #17

 P: n/a Sigurd Stenersen wrote: Carl Daniel [VC++ MVP] wrote: Tom is correct. I didn't say he's wrong. I pointed out that the C-style cast does the same thing no matter what you use it for. That depends on how you interpret "does the same thing". Sometimes a C-style cast will result in a change of value representation (e.g. cast from base to derived) and sometimes it wont. For example, if you wanted to cast from base to derived but prevent any change in value representation (this-pointer adjustments), you'd have to use a reinterpret_cast, because in that context a C-style cast will behave as a static_cast. Contrast this to C where casts between any two pointer types are the equivalent of a reinterpret_cast. -cd Nov 17 '05 #18

 P: n/a On Fri, 8 Oct 2004 17:12:18 +0200, "Sigurd Stenersen" wrote: Carl Daniel [VC++ MVP] wrote: Sigurd Stenersen wrote: Tom Widmer wrote: It is context dependent. A C-style cast can act as a static_cast, a const_cast or a reinterpret_cast, as well as combinations of those. It can also perform casts that can't even be done by reinterpret_cast, such as casting to a private base class. It does the same thing no matter what the context is - it treats something of one type like it actually is some other type. Tom is correct.I didn't say he's wrong. I pointed out that the C-style cast does the samething no matter what you use it for. C-style casting to, say, a "std::string const&" might involve a constructor call, a conversion operator call, a reference coercion, a qualification adjustment or a no-op, depending on the source type. I don't consider all of those to be the same thing! Tom Nov 17 '05 #19

 P: n/a Carl Daniel [VC++ MVP] wrote: Sigurd Stenersen wrote: Carl Daniel [VC++ MVP] wrote: Tom is correct. I didn't say he's wrong. I pointed out that the C-style cast does the same thing no matter what you use it for. That depends on how you interpret "does the same thing". Sometimes a C-style cast will result in a change of value representation (e.g. cast from base to derived) No, that's when you're instantiating rather than casting. For example, if you wanted to cast from base to derived but prevent any change in value representation (this-pointer adjustments), you'd have to use a reinterpret_cast, because in that context a C-style cast will behave as a static_cast. Yeah. And now you're talking about something that's just not possible to do with a C-style cast. Contrast this to C where casts between any two pointer types are the equivalent of a reinterpret_cast. Yes, that is one of the differences between C-style and C++ style casts. -- Sigurd http://utvikling.com Nov 17 '05 #20

 P: n/a Tom Widmer wrote: On Fri, 8 Oct 2004 16:20:27 +0200, "Sigurd Stenersen" wrote: Tom Widmer wrote: It is context dependent. A C-style cast can act as a static_cast, a const_cast or a reinterpret_cast, as well as combinations of those. It can also perform casts that can't even be done by reinterpret_cast, such as casting to a private base class. It does the same thing no matter what the context is - it treats something of one type like it actually is some other type. Depending on the relationship, the cast might cause a function to be called Well, that's where I'm arguing that you're not casting but rather instantiating. might need a cast pointer value to be adjusted (multiple inheritence) That's a good point and I didn't think of that. But in this case it could be argued that with multiple inheritance, you get an implicit type conversion operator and that you're not casting but rather that you're calling this implicit operator. Further proof of this is that you can make this operator explicit and it'll certainly be called. or it might not need to do anything at runtime. const_cast, static_cast and reinterpret_cast give you more control, since each of them will only do a subset of what a C-style cast can do. Yes, I do realize that. You've almost convinced me that I should to start using them... Casting to certain types results in the creation of a temporary object of the destination type. All casts to non-reference types give you a temporary (or rvalue), unless I'm mistaken. int i; (char) i; No, I don't think so. The compiler will use the lvalue (i) for this. However, that's not related to context but rather it's related to the destination type. The point is that what the cast dose is related to both source and destination type, and the relationship between those types. Yes, I can see that that is true with your perception of what a cast is. And I also see that several skilled people on this newsgroup agree with you. And I still feel like I have a valid point. -- Sigurd http://utvikling.com Nov 17 '05 #21

 P: n/a Igor Tandetnik wrote: [excellent explanation of C++ typecasts snipped] That's what people mean when they say C-style cast is context-sensitive - it behaves differently when casting between related types than when casting between unrelated ones; it takes the relation between the two types into account. Contrast this with reinterpret_cast, which just blindly takes the bit layout as is, and treats it as a different type. I disagree with your conclusion - it's the C++ style casts that behave differently depending on what you describe here, the C-style cast behaves the same way all over the place. In other words : when you keep changing the "measuring system" while "measuring" you are quite likely to get different "results" for the same "input"... -- Sigurd http://utvikling.com Nov 17 '05 #22

 P: n/a Tom Widmer wrote: On Fri, 8 Oct 2004 15:32:29 +0200, "Sigurd Stenersen" wrote: However, I've tried it with A having only a char member and nothing else, but no access violation occured in this case, either. (I compiled the example both in debug and release mode.) I think it should have produced some runtime error, especially in debug mode, shouldn't it? No, it's *legal*. You told the compiler you knew what you were doing... To put it more precisely, the code is well-formed but exhibits undefined behaviour. ....which it would not do, of course, if you knew what you were doing. It's usually better to stick to the truth. Life is simpler that way. ;o) -- Sigurd http://utvikling.com Nov 17 '05 #23

 P: n/a Tom Widmer wrote: On Fri, 8 Oct 2004 17:12:18 +0200, "Sigurd Stenersen" wrote: Carl Daniel [VC++ MVP] wrote: Tom is correct. I didn't say he's wrong. I pointed out that the C-style cast does the same thing no matter what you use it for. C-style casting to, say, a "std::string const&" might involve a constructor call, a conversion operator call, a reference coercion, a qualification adjustment or a no-op, depending on the source type. I don't consider all of those to be the same thing! My point precisely. It's only the NOP that actually *is* a C-style cast. -- Sigurd http://utvikling.com Nov 17 '05 #24

 P: n/a "Sigurd Stenersen" wrote in message news:uB**************@TK2MSFTNGP15.phx.gbl Carl Daniel [VC++ MVP] wrote: For example, if you wanted to cast from base to derived but prevent any change in value representation (this-pointer adjustments), you'd have to use a reinterpret_cast, because in that context a C-style cast will behave as a static_cast. Yeah. And now you're talking about something that's just not possible to do with a C-style cast. Is too: class B {}; class D : public B {}; B* pB = new D(); D* pD1 = (D*)pB; // equivalent to static_cast D* pD2 = (D*)(void*)pB; // equivalent to reinterpret_cast The intermediate cast to void* is used here to lose context - the relation between B and D. C-style cast (or more precisely, explicit type conversion expression as defined in C++ standard 5.4) is context-sensitive after all. It it were completely context-insensitive and just "treat something of one type like it actually is some other type", then it should be transitive, right (assuming there's no loss of information due to casting to a smaller type)? But it's clearly not. -- With best wishes, Igor Tandetnik "On two occasions, I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able to rightly apprehend the kind of confusion of ideas that could provoke such a question." -- Charles Babbage Nov 17 '05 #25

 P: n/a On Fri, 8 Oct 2004 18:24:10 +0200, "Sigurd Stenersen" wrote: Tom Widmer wrote: On Fri, 8 Oct 2004 17:12:18 +0200, "Sigurd Stenersen" wrote: Carl Daniel [VC++ MVP] wrote: Tom is correct. I didn't say he's wrong. I pointed out that the C-style cast does the same thing no matter what you use it for. C-style casting to, say, a "std::string const&" might involve a constructor call, a conversion operator call, a reference coercion, a qualification adjustment or a no-op, depending on the source type. I don't consider all of those to be the same thing!My point precisely. It's only the NOP that actually *is* a C-style cast. They are all C-style casts. I think there is a difference of opinion on what a C-style cast is, and this has lead to this whole argument. A C-style cast is generally meant to refer to any expression of the form: (T) cast-expression where T is a type. In other words, a C-style cast is synonymous with what the C++ standard calls "Explicit type conversion (cast notation)". Do you disagree? Tom Nov 17 '05 #26

 P: n/a "Sigurd Stenersen" wrote in message news:ux**************@TK2MSFTNGP11.phx.gbl Igor Tandetnik wrote: [excellent explanation of C++ typecasts snipped] That's what people mean when they say C-style cast is context-sensitive - it behaves differently when casting between related types than when casting between unrelated ones; it takes the relation between the two types into account. Contrast this with reinterpret_cast, which just blindly takes the bit layout as is, and treats it as a different type. I disagree with your conclusion - it's the C++ style casts that behave differently depending on what you describe here, the C-style cast behaves the same way all over the place. Can your formally define the assertion "behaves the same way" ? It appears that the whole discussion keeps revolving around the fact that you understand the term "the same way" differently than all other participants. Actually, before this discussion can continue, can you please formally define the following: 1. The meaning of the term "C-style cast". Most participants understand it as referring to a syntactical construct of Explicit type conversion (cast notation), as defined in C++ standard 5.4. Yet you seem to argue that it is a true C-style cast in some cases, and not really a C-style cast in other cases. 2. How you believe a C-style cast, as defined by you in item 1, behaves or should behave. 3. Your criterion for when behavior in one case is sufficiently similar to that in antother case, so that you can say that something "behaves the same way" in both cases. In other words : when you keep changing the "measuring system" while "measuring" you are quite likely to get different "results" for the same "input"... That's exactly why I would like you to formally establish a point of reference, since yours appears to be quite unorthodox, to the point where fundamental term definitions implicitly understood by most participants can no longer be relied upon in the discussion. Thus I would like them to be explicitly stated up front, then we can continue discussion within your set of axioms. -- With best wishes, Igor Tandetnik "On two occasions, I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able to rightly apprehend the kind of confusion of ideas that could provoke such a question." -- Charles Babbage Nov 17 '05 #27

 P: n/a Igor Tandetnik wrote: "Sigurd Stenersen" wrote in message news:uB**************@TK2MSFTNGP15.phx.gbl Carl Daniel [VC++ MVP] wrote: For example, if you wanted to cast from base to derived but prevent any change in value representation (this-pointer adjustments), you'd have to use a reinterpret_cast, because in that context a C-style cast will behave as a static_cast. Yeah. And now you're talking about something that's just not possible to do with a C-style cast. Is too: class B {}; class D : public B {}; B* pB = new D(); D* pD1 = (D*)pB; // equivalent to static_cast D* pD2 = (D*)(void*)pB; // equivalent to reinterpret_cast Yeah. And now you're talking about something that's just not possible to do with a single C-style cast. -- Sigurd http://utvikling.com Nov 17 '05 #28

 P: n/a Tom Widmer wrote: On Fri, 8 Oct 2004 18:24:10 +0200, "Sigurd Stenersen" wrote: My point precisely. It's only the NOP that actually *is* a C-style cast. They are all C-style casts. I think there is a difference of opinion on what a C-style cast is, and this has lead to this whole argument. Yes, that is my perception too. A C-style cast is generally meant to refer to any expression of the form: (T) cast-expression where T is a type. You have to take it a bit further. Most C++ developers would agree that (T) ce means exactly the same as T(ce) and most of them would also label both as C-style casts. And thus, if given struct X { X(); } then X(ce) is *not* a cast but an instantiation, and therefore (X) ce is not a cast but an instantiation. I realize that "most developers" is by now probably reduced to "one developer" in this newsgroup, but I still have a valid point... In other words, a C-style cast is synonymous with what the C++ standard calls "Explicit type conversion (cast notation)". Do you disagree? I don't know. I don't have the standard handy, and I really hate formalities so let's not go there. -- Sigurd http://utvikling.com Nov 17 '05 #29

 P: n/a "Sigurd Stenersen" wrote in message news:%2****************@TK2MSFTNGP11.phx.gbl Igor Tandetnik wrote: "Sigurd Stenersen" wrote in message news:uB**************@TK2MSFTNGP15.phx.gbl Carl Daniel [VC++ MVP] wrote: For example, if you wanted to cast from base to derived but prevent any change in value representation (this-pointer adjustments), you'd have to use a reinterpret_cast, because in that context a C-style cast will behave as a static_cast. Yeah. And now you're talking about something that's just not possible to do with a C-style cast. Is too: class B {}; class D : public B {}; B* pB = new D(); D* pD1 = (D*)pB; // equivalent to static_cast D* pD2 = (D*)(void*)pB; // equivalent to reinterpret_cast Yeah. And now you're talking about something that's just not possible to do with a single C-style cast. How is this observation related to the issue of whether C-style cast behaves "the same way" or not? I fail to see your point. Can you please elaborate (preferably after you answer my other post about establishing the terminology)? -- With best wishes, Igor Tandetnik "On two occasions, I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able to rightly apprehend the kind of confusion of ideas that could provoke such a question." -- Charles Babbage Nov 17 '05 #30

 P: n/a Igor Tandetnik wrote: "Sigurd Stenersen" wrote in message news:%2****************@TK2MSFTNGP11.phx.gbl Igor Tandetnik wrote: "Sigurd Stenersen" wrote in message news:uB**************@TK2MSFTNGP15.phx.gbl Carl Daniel [VC++ MVP] wrote:> For example, if you wanted to cast from base to derived but> prevent any change in value representation (this-pointer> adjustments), you'd have to use a reinterpret_cast, because in> that context a C-style cast will behave as a static_cast. Yeah. And now you're talking about something that's just not possible to do with a C-style cast. Is too: class B {}; class D : public B {}; B* pB = new D(); D* pD1 = (D*)pB; // equivalent to static_cast D* pD2 = (D*)(void*)pB; // equivalent to reinterpret_cast Yeah. And now you're talking about something that's just not possible to do with a single C-style cast. How is this observation related to the issue of whether C-style cast behaves "the same way" or not? Isn't that pretty clear ? You're using an example that doesn't illustrate *anything* but the fact that in order to achieve a certain C++ cast using C-style casts you have to use *two* of them. I fail to see your point. Can you please elaborate I already did. Repeatedly. (preferably after you answer my other post about establishing the terminology)? I already did. -- Sigurd http://utvikling.com Nov 17 '05 #32

 P: n/a "Sigurd Stenersen" wrote in message news:Of**************@TK2MSFTNGP12.phx.gbl... The case is not the same for actual typecasts that use the same notation, e.g. int i; (char) i; is the same as int i; char(i); which is a cast and not an instantiation. Hmmmmm... float f; (int) f; Cast or instantiation? -- Truth, James Curran Home: www.noveltheory.com Work: www.njtheater.com Blog: www.honestillusion.com Day Job: www.partsearch.com (note new day job!) Nov 17 '05 #34

 P: n/a James Curran wrote: "Sigurd Stenersen" wrote in message news:Of**************@TK2MSFTNGP12.phx.gbl... The case is not the same for actual typecasts that use the same notation, e.g. int i; (char) i; is the same as int i; char(i); which is a cast and not an instantiation. Hmmmmm... float f; (int) f; Cast or instantiation? That's a cast, and not a NOP. Good point, even though it's the same in C. -- Sigurd http://utvikling.com Nov 17 '05 #35

 P: n/a Igor Tandetnik wrote a lot of schtuff I'll give you the last word here, Igor, as I'm not operating at the same level of abstraction (or political or pedantic correctness or whatever the hey it is) as you are, and I can't comfortably move around up there (it would take me forever if I tried, and that would contradict the way I've been successfully producing excellent results over the past seventeen years in the software industry). If that means that you're right and I'm wrong, then you're right and I'm wrong. -- Sigurd http://utvikling.com Nov 17 '05 #36

 P: n/a Sigurd Stenersen wrote: Carl Daniel [VC++ MVP] wrote: That depends on how you interpret "does the same thing". Sometimes a C-style cast will result in a change of value representation (e.g. cast from base to derived) No, that's when you're instantiating rather than casting. Wrong. Igor's already provided an example. -cd Nov 17 '05 #37

 P: n/a On Fri, 8 Oct 2004 18:59:26 +0200, "Sigurd Stenersen" wrote: Tom Widmer wrote: On Fri, 8 Oct 2004 18:24:10 +0200, "Sigurd Stenersen" wrote: My point precisely. It's only the NOP that actually *is* a C-style cast. They are all C-style casts. I think there is a difference of opinion on what a C-style cast is, and this has lead to this whole argument.Yes, that is my perception too. A C-style cast is generally meant to refer to any expression of the form: (T) cast-expression where T is a type.You have to take it a bit further.Most C++ developers would agree that (T) cemeans exactly the same as T(ce)and most of them would also label both as C-style casts. I can agree to disagree, but I, and I think most others, actually consider a C-style cast to be a syntatic rather than semantic feature, and to look like your former case above. The fact that the latter can perform all the same conversions as the former may even come as a surprise to some, since I think (hope?) most people only ever use the latter as an alternative syntax for a static_cast, not as an alternative syntax for, e.g., reinterpret_cast. Tom Nov 17 '05 #38

 P: n/a "Tom Widmer" wrote in message news:38********************************@4ax.com On Fri, 8 Oct 2004 18:59:26 +0200, "Sigurd Stenersen" wrote: Most C++ developers would agree that (T) ce means exactly the same as T(ce) and most of them would also label both as C-style casts. The fact that the latter can perform all the same conversions as the former may even come as a surprise to some It should not, really. C++ standard 5.2.3/1: A simple-type-specifier (7.1.5) followed by a parenthesized expression-list constructs a value of the specified type given the expression list. If the expression list is a single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (5.4). -- With best wishes, Igor Tandetnik "On two occasions, I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able to rightly apprehend the kind of confusion of ideas that could provoke such a question." -- Charles Babbage Nov 17 '05 #39

 P: n/a On Mon, 11 Oct 2004 09:40:11 -0400, "Igor Tandetnik" wrote: "Tom Widmer" wrote in messagenews:38********************************@4ax.com On Fri, 8 Oct 2004 18:59:26 +0200, "Sigurd Stenersen" wrote: Most C++ developers would agree that (T) ce means exactly the same as T(ce) and most of them would also label both as C-style casts. The fact that the latter can perform all the same conversions as the former may even come as a surprise to someIt should not, really. C++ standard 5.2.3/1:A simple-type-specifier (7.1.5) followed by a parenthesizedexpression-list constructs a value of the specified type given theexpression list. If the expression list is a single expression, the typeconversion expression is equivalent (in definedness, and if defined inmeaning) to the corresponding cast expression (5.4). Indeed, but given that most people regularly make use of "explicit type conversion (functional notation)", the fact that it might actually be performing a reinterpret_cast or a const_cast is a bit alarming IMHO. I've never used it for anything other than a static_cast, so it's a shame that the standard doesn't enforce this. Tom Nov 17 '05 #40

 P: n/a int i; (char) i; I am sure it is an rvalue. Just try this: int i; (char) i = 123; // error However, on non-builtin types it is indeed an lvalue: struct A { A(int) {} }; int i; (A)i = (A)4; The result is a temporary lvalue. So, builtin types do not instantiate but classes do? "Sigurd Stenersen" wrote: Tom Widmer wrote: On Fri, 8 Oct 2004 16:20:27 +0200, "Sigurd Stenersen" wrote: Tom Widmer wrote: It is context dependent. A C-style cast can act as a static_cast, a const_cast or a reinterpret_cast, as well as combinations of those. It can also perform casts that can't even be done by reinterpret_cast, such as casting to a private base class. It does the same thing no matter what the context is - it treats something of one type like it actually is some other type. Depending on the relationship, the cast might cause a function to be called Well, that's where I'm arguing that you're not casting but rather instantiating. might need a cast pointer value to be adjusted (multiple inheritence) That's a good point and I didn't think of that. But in this case it could be argued that with multiple inheritance, you get an implicit type conversion operator and that you're not casting but rather that you're calling this implicit operator. Further proof of this is that you can make this operator explicit and it'll certainly be called. or it might not need to do anything at runtime. const_cast, static_cast and reinterpret_cast give you more control, since each of them will only do a subset of what a C-style cast can do. Yes, I do realize that. You've almost convinced me that I should to start using them... Casting to certain types results in the creation of a temporary object of the destination type. All casts to non-reference types give you a temporary (or rvalue), unless I'm mistaken. int i; (char) i; No, I don't think so. The compiler will use the lvalue (i) for this. However, that's not related to context but rather it's related to the destination type. The point is that what the cast dose is related to both source and destination type, and the relationship between those types. Yes, I can see that that is true with your perception of what a cast is. And I also see that several skilled people on this newsgroup agree with you. And I still feel like I have a valid point. -- Sigurd http://utvikling.com Nov 17 '05 #41

 P: n/a Pieter de Goeje wrote: int i;(char) i;I am sure it is an rvalue. Just try this:int i;(char) i = 123; // errorHowever, on non-builtin types it is indeed an lvalue:struct A { A(int) {} };int i;(A)i = (A)4;The result is a temporary lvalue. No. Temporary objects are rvalues. I don't know if it's possible to define the terms lvalue and rvalue WRT C++ except to list those things the standard says they are; a more abstract definition eludes me. I once posted this as an example of a sort of built-in joke: ***** http://groups.google.com/groups?selm...m7p6%404ax.com struct X { }; void g(X&); void f() { X() = X(); g(X() = X()); g(X()); // No good } Note that above, the result of assigning one rvalue to another rvalue is a modifiable lvalue. :) ***** The difference between the rvalues produced by X() and int() is that the former has member functions you can call on it, and you're allowed to call them, including the assignment operator. So, builtin types do not instantiate but classes do? I don't get the question. -- Doug Harrison Microsoft MVP - Visual C++ Nov 17 '05 #42

 P: n/a "Doug Harrison [MVP]" wrote in message news:pj********************************@4ax.com So, builtin types do not instantiate but classes do? I don't get the question. It's a reference to Sigurd Stenersen's insistence that some instances of C-style cast expression are "real" casts, and others are kinda sorta not really casts but, you know, "instantiations" - a position that got everyone baffled for a while. You'll have to read the whole thread to understand this fine point. It's not really all that interesting. -- With best wishes, Igor Tandetnik "On two occasions, I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able to rightly apprehend the kind of confusion of ideas that could provoke such a question." -- Charles Babbage Nov 17 '05 #43

 P: n/a Pieter de Goeje wrote: I am sure it is an rvalue. Just try this: int i; (char) i = 123; // error Yes. So this is obviously a cast and not an instantiation. However, on non-builtin types it is indeed an lvalue: struct A { A(int) {} }; int i; (A)i = (A)4; The result is a temporary lvalue. Yes. And here you're not casting, you're instantiating. Twice. -- Sigurd http://utvikling.com Nov 17 '05 #44

 P: n/a Igor Tandetnik wrote: "Doug Harrison [MVP]" wrote in message news:pj********************************@4ax.com So, builtin types do not instantiate but classes do? I don't get the question. It's a reference to Sigurd Stenersen's insistence that some instances of C-style cast expression are "real" casts, and others are kinda sorta not really casts but, you know, "instantiations" That is almost correct. Except when you *do* instantiate you're *not using* a "C-style cast expression". It just looks kinda similar. a position that got everyone baffled for a while. Whoo-hoo ! I managed to make a lot of highly skilled people stop and think for a while. That's quite an achievement. Thank you so much for pointing that out, you just made my day. You'll have to read the whole thread to understand this fine point. That's a statement about you. It's not really all that interesting. That's another statement about you. -- Sigurd http://utvikling.com Nov 17 '05 #45