Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Does cast to its own type create a temporary copy?

94 views
Skip to first unread message

Niels Dekker - no return address

unread,
Nov 14, 2008, 11:08:54 AM11/14/08
to
Does static_cast<int>(argc) create a temporary copy of argc, in the following
little program?

////////////////////////////////////////
#include <cassert>

void Inc(const int& input, int& output)
{
output = input + 1;
assert( output == (input + 1) );
}

int main(int argc, char**)
{
Inc( static_cast<int>(argc), argc );
}
////////////////////////////////////////

I tried both GCC 4.3.2 and MSVC 9. On MSVC, the static_cast<int> doesn't have
any effect (because argc is an int already), so the input and the output
argument refer to the very same object. Causing the assert to fail. While
GCC doesn't get me the assert failure, so apparently GCC has the input
argument referring to a temporary copy of argc. Is the static_cast<int>
indeed supposed to create a temporary copy?


Kind regards,
--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

annamalai

unread,
Nov 14, 2008, 5:25:59 PM11/14/08
to
On Nov 14, 10:08 am, "Niels Dekker - no return address"

<nore...@this.is.invalid> wrote:
> argument referring to a temporary copy of argc. Is the static_cast<int>
> indeed supposed to create a temporary copy?

From the C++ draft standard (n2798.pdf page 98 Section 5.2.9p1)

"The result of the expression static_cast<T>(v) is the result of
converting the expression v to type T. If T is an lvalue reference
type, the result is an lvalue; otherwise, the result is an rvalue. The
static_cast operator shall not cast away constness."

Since in your code T is not an lvalue reference type, the result is an
rvalue. And so a temporary object is created. To avoid temporary
object you can cast to reference type as follows:

RL1 1017 $ cat cast.cc
#include <iostream>
#include <cassert>

struct T {
T() { std::cout << "T()" << std::endl; }
T(const T&) { std::cout << "T(const T&)" << std::endl; }
};

void Inc(const T& input, T& output) {
if ( &input == &output )
std::cout << "No temporary obj created." << std::endl;
else
std::cout << "Temporary obj created." << std::endl;
}

int main() {
T obj;
Inc( static_cast<T&>(obj), obj );
Inc( static_cast<T>(obj), obj );
}


RL1 1018 $ g++ -Wall -Wall -O3 -pedantic cast.cc
RL1 1019 $ ./a.out
T()
No temporary obj created.
T(const T&)
Temporary obj created.
RL1 1020 $ g++ --version
g++ (GCC) 4.1.1 20070105 (Red Hat 4.1.1-52)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

RL1 1021 $

Rgds,
anna

--
Used Car For Sale ($2800/-) 1998 Ford Explorer XLT (Mileage 189000)
Naperville, IL 60563, USA. Will sell by 2nd or 3rd week of Dec 2008.

Seungbeom Kim

unread,
Nov 14, 2008, 5:58:23 PM11/14/08
to
Niels Dekker - no return address wrote:
> Does static_cast<int>(argc) create a temporary copy of argc, in the
> following
> little program?
>
> ////////////////////////////////////////
> #include <cassert>
>
> void Inc(const int& input, int& output)
> {
> output = input + 1;
> assert( output == (input + 1) );
> }
>
> int main(int argc, char**)
> {
> Inc( static_cast<int>(argc), argc );
> }
> ////////////////////////////////////////

5.2.9/1:


| The result of the expression static_cast<T>(v) is the result of

| converting the expression v to type T. If T is a reference type,


| the result is an lvalue; otherwise, the result is an rvalue.

| Types shall not be defined in a static_cast. The static_cast
| operator shall not cast away constness (5.2.11)."

Here it says the result is an rvalue for static_cast<int>. Furthermore,

5.2.9/2:
| An expression e can be explicitly converted to a type T using a
| static_cast of the form static_cast<T>(e) if the declaration “T t(e);”
| is well-formed, for some invented temporary variable t (8.5).
| The effect of such an explicit conversion is the same as performing
| the declaration and initialization and then using the temporary
| variable as the result of the conversion. The result is an lvalue
| if T is a reference type (8.3.2), and an rvalue otherwise. The
| expression e is used as an lvalue if and only if the initialization
| uses it as an lvalue.

Here it says explicitly that a temporary variable is created and used.

--
Seungbeom Kim

Niels Dekker - no return address

unread,
Nov 16, 2008, 12:01:58 PM11/16/08
to
Seungbeom Kim wrote:
> 5.2.9/1:
> | The result of the expression static_cast<T>(v) is...

>
> Here it says the result is an rvalue for static_cast<int>.
> Furthermore,
>
> 5.2.9/2:
> | An expression e can be explicitly converted to a type T...

> Here it says explicitly that a temporary variable is created and used.

Thank you, Seungbeom! Also thanks, anna! I just realized I should have
disabled the Microsoft-specific language extensions ("/Za"), when I did
the MSVC compilation.

MSVC *does* create a temporary variable when doing static_cast<int>,
when its language extensions are disabled.

Kind regards, Niels


--

blargg

unread,
Nov 17, 2008, 2:14:57 AM11/17/08
to
Niels Dekker wrote:
> Does static_cast<int>(argc) create a temporary copy of argc, in the following
> little program?
>
> ////////////////////////////////////////
> #include <cassert>
>
> void Inc(const int& input, int& output)
> {
> output = input + 1;
> assert( output == (input + 1) );
> }
>
> int main(int argc, char**)
> {
> Inc( static_cast<int>(argc), argc );
> }
[...]

I'm interested in what results you get for similar constructs, which a
compiler might also be tempted to meddle with:

Inc( +argc, argc );
Inc( argc+0, argc );

--

Niels Dekker - no return address

unread,
Nov 17, 2008, 8:32:39 PM11/17/08
to
blargg wrote:
>> ////////////////////////////////////////
>> #include <cassert>
>>
>> void Inc(const int& input, int& output)
>> {
>> output = input + 1;
>> assert( output == (input + 1) );
>> }
>>
>> int main(int argc, char**)
>> {
>> Inc( static_cast<int>(argc), argc );
>> }
> [...]
>
> I'm interested in what results you get for similar constructs, which a
> compiler might also be tempted to meddle with:
>
> Inc( +argc, argc );
> Inc( argc+0, argc );


Nice suggestion! For both +argc and argc+0, MSVC 9 (SP1) appears to create
a
temporary (I don't get assert failures on those two), even when
Microsoft-specific language extensions are enabled.


Kind regards, Niels

Niels Dekker - no return address

unread,
Nov 19, 2008, 4:43:32 PM11/19/08
to
annamalai wrote:
> #include <iostream>
> #include <cassert>
>
> struct T {
> T() { std::cout << "T()" << std::endl; }
> T(const T&) { std::cout << "T(const T&)" << std::endl; }
> };
>
> void Inc(const T& input, T& output) {
> if ( &input == &output )
> std::cout << "No temporary obj created." << std::endl;
> else
> std::cout << "Temporary obj created." << std::endl;
> }
>
> int main() {
> T obj;
> Inc( static_cast<T&>(obj), obj );
> Inc( static_cast<T>(obj), obj );
> }

Your struct T and my Inc function have made it into a compiler bug
report :-) Apparently the CodeGear C++ compiler doesn't always create
a temporary when it should, as reported by Fraser Ross: Report #69102 -
"static_cast a type to the same type"
http://qc.codegear.com/wc/qcmain.aspx?d=69102

Kind regards, Niels

--

0 new messages