c++ - Order of operator execution at function exit
- MR (34/34) Jan 26 2010 Given the class String.
- Heinz Saathoff (50/98) Jan 27 2010 When charFn() ends rStr is no longer valid (destroyed by Destructor).
- MR (18/18) Jan 27 2010 Thanks for the clarification. I now must buy a copy of the standard. I c...
- Bertel Brander (42/65) Jan 27 2010 That is not the case for C or C++, more over it would
- Heinz Saathoff (5/7) Jan 28 2010 His own String class might have a "operator char*()"
- Bertel Brander (2/9) Jan 28 2010 Sorry, my fault, I had read String as std::string
Given the class String. String contains functions including constructors, a destructor, nd a number of general functions that includes a char* casting operator and an assignment operator=() function. Define two functions in a program: char* charFn() { String rStr; <Process to create data in rStr> <rStr contains corrrect code here> return (char*)rStr; } String strFn() { String rStr; <Process to create data in rStr> <rStr contains corrrect code here> return rStr; } -- MAIN Code -- String str; str = strFn(); // Code works correctly - str contains expected data. str = charFn(); // This FAILS - str is empty. Investigations show that in the charFn() case, the destructor for 'rStr' is called BEFORE the completion of the assignment operator in the main code. This is NOT the case for the call to strFn(). In this case, the assignment operator is called before the destructor for the internal variable 'rStr'. I believe that this is incorrect semantics. The assignment operation should be invoked before the destructor for the data being returned via the (char*) casting operator.
Jan 26 2010
Hello, MR wrote...Given the class String. String contains functions including constructors, a destructor, nd a number of general functions that includes a char* casting operator and an assignment operator=() function. Define two functions in a program: char* charFn() { String rStr; <Process to create data in rStr> <rStr contains corrrect code here> return (char*)rStr; }When charFn() ends rStr is no longer valid (destroyed by Destructor). The compiler can implement charFn() this way: void charFn(char* & __result) { String rStr; // ..... __result = (char*)rStr; // leave charFn, destruct rStr rStr.~rStr(); // Storage allocated by rStr is freed } void main() { char *cpt; charFn(cpt); // compiler generates this from cpt=charFn(); // the call to charFn is a sequence point so all // objects in charFn are destroyed now. That's why // cpt points to non existing memory now (assuming // String class did not use static or non freed heap space }String strFn() { String rStr; <Process to create data in rStr> <rStr contains corrrect code here> return rStr; }again compiler generated code similar as above: void strFn(String & __result) { String rStr; // ..... __result.operator=(rStr); // copy rStr // leave strFn, destruct rStr rStr.~rStr(); // Storage allocated by rStr is freed, // but __result still has copy of rStr! } void main() { String str; // construct by default constructor strFn(str); // compiler generates this from str=strFn(); // strFn is a sequence point but this has no influence // on str. So str is still valid and can be used here }-- MAIN Code -- String str; str = strFn(); // Code works correctly - str contains expected data.so it should.str = charFn(); // This FAILS - str is empty.undifined because returnd char* may point to arbitrary memory location.Investigations show that in the charFn() case, the destructor for 'rStr' is called BEFORE the completion of the assignment operator in the main code.Right, the destructor is called at last part of the function. Function return defines a sequnce point (see ISO 14882, 1.19.17)This is NOT the case for the call to strFn(). In this case, the assignment operator is called before the destructor for the internal variable 'rStr'.Because the returned String is returned by value! if it were returned by reference it would also be undefined.I believe that this is incorrect semantics. The assignment operation should be invoked before the destructor for the data being returned via the (char*) casting operator.The behaviour is correct from the standard point of view. - Heinz
Jan 27 2010
Thanks for the clarification. I now must buy a copy of the standard. I certainly believe your interpretation; I just think the standard is wrong :) In all cases where an object is returned through an expression, the object life should extend to the completion of the expression. In my case if I were to use a expression such as: char* ptr; ptr = charFn(); ...then use ptr later, it should be undefined. For the case under consideration String nStr; nStr = charFn(); ... where the semantics of the assignment makes a copy of the char* data, the object, were the object life to extend through the assignment, there would be no problem. It seems logical for the semantics to follow this logic rather than that defined by the standard. Again, thanks for the clarification. Milt
Jan 27 2010
MR skrev:Thanks for the clarification. I now must buy a copy of the standard. I certainly believe your interpretation; I just think the standard is wrong :)The standard is always, by definition, right.In all cases where an object is returned through an expression, the object life should extend to the completion of the expression.That is not the case for C or C++, more over it would be virtually impossible to do in C and C++,In my case if I were to use a expression such as: char* ptr; ptr = charFn(); ...then use ptr later, it should be undefined. For the case under consideration String nStr; nStr = charFn(); ... where the semantics of the assignment makes a copy of the char* data, the object, were the object life to extend through the assignment, there would be no problem. It seems logical for the semantics to follow this logic rather than that defined by the standard.If your code should work as you think it should, when should the object then be freed? The compiler has no ways to know when to free the object. Lets look at a bit more advanced example: one.h: struct SomeStruct { char* p; }; void func(SomeStruct& someStruct); one.cpp: char* charFn() { String rStr; <Process to create data in rStr> <rStr contains corrrect code here> return (char*)rStr; } void func(SomeStruct& someStruct) { if(something) someStruct.p = charFn(); } another.cpp: void pop() { SomeStruct someStruct; func(someStruct); } If the compiler were to make a copy of the string in charFn, it must free that string at some point. In the example above that would have to happen in the function pop, but the compiler has absolutely no way of knowing if someStruct.p points at something that it must free. There is to ways to overcome this, you could call new[] in charFn and delete[] in pop. Or the more easy way, make charFn return a string. Also note that the cast in charFn is not valid.
Jan 27 2010
Hello, Bertel Brander wrote...Also note that the cast in charFn is not valid.His own String class might have a "operator char*()" as a user defined conversion operator defined. - Heinz
Jan 28 2010
Heinz Saathoff skrev:Hello, Bertel Brander wrote...Sorry, my fault, I had read String as std::stringAlso note that the cast in charFn is not valid.His own String class might have a "operator char*()" as a user defined conversion operator defined.
Jan 28 2010