cleanup of temporary objects

Y

yevvio

Hi, sorry, messed up my previous post...

Consider the following code:

class A {
int x;
public:
A() { printf("In A()\n"); x = 5; }
~A() { printf("In ~A()\n"); }
operator int *() { printf("In int *()\n"); return &x; }
};

A f1()
{
printf("in f1()\n");
return A();
}

void foo(int *p) { printf("in foo()\n"); }

int main()
{
foo(f1());
printf("After foo()\n");
return 0;
}

I have always thought this code is wrong because the temporary object
A would be destroyed after calling int *() operator and before
entering foo(), so the pointer p would point to freed memory. However
i complied the code in both vs2005 and gcc compilers and ran it, it
complies fine and the result in both cases is the following:

in f1()
In A()
In int *()
in foo()
In ~A()
After foo()

That means that temporary A is kept alive for the duration of function
foo().
So what should be correct behaviour according to c++ standard
regarding when the temporary is freed? Is the code above portable?

Thanks
Yev
 
J

James Kanze

Consider the following code:
class A {
int x;
public:
A() { printf("In A()\n"); x = 5; }
~A() { printf("In ~A()\n"); }
operator int *() { printf("In int *()\n"); return &x; }
};
A f1()
{
printf("in f1()\n");
return A();
}
void foo(int *p) { printf("in foo()\n"); }
int main()
{
foo(f1());
printf("After foo()\n");
return 0;
}
I have always thought this code is wrong because the temporary
object A would be destroyed after calling int *() operator and
before entering foo(), so the pointer p would point to freed
memory. However i complied the code in both vs2005 and gcc
compilers and ran it, it complies fine and the result in both
cases is the following:
in f1()
In A()
In int *()
in foo()
In ~A()
After foo()
That means that temporary A is kept alive for the duration of
function foo(). So what should be correct behaviour according
to c++ standard regarding when the temporary is freed? Is the
code above portable?

According to the standard, the lifetime of a temporary is until
the end of the full expression in which it was created. There
are a few special cases where the lifetime may be extended, but
it is never shorter. And unless you are in one of the special
cases where it is extended, it may not be longer.

Note that this wasn't always the case. When I was learning C++,
it was more or less unspecified, and could be anywhere between
the "use" of the temporary (here, the call of the function
operator int*()) and the end of the block. The literature at
the time warned of this potential problem---perhaps you have
been reading something out of data. (FWIW: of the two compilers
I used at the time, CFront destructed at the end of the block,
and g++ after first use. Even today, by default, Sun CC defers
destruction till the end of the block, in order to avoid
breaking code written for CFront which depended on this.)
 
T

Triple-DES

Hi, sorry, messed up my previous post...

Consider the following code:

class A {
int x;
public:
A() { printf("In A()\n"); x = 5; }
~A() { printf("In ~A()\n"); }
operator int *() { printf("In int *()\n"); return &x; }

};

A f1()
{
printf("in f1()\n");
return A();

}

void foo(int *p) { printf("in foo()\n"); }

int main()
{
foo(f1());
printf("After foo()\n");
return 0;

}

I have always thought this code is wrong because the temporary object
A would be destroyed after calling int *() operator and before
entering foo(), so the pointer p would point to freed memory. However
i complied the code in both vs2005 and gcc compilers and ran it, it
complies fine and the result in both cases is the following:

in f1()
In A()
In int *()
in foo()
In ~A()
After foo()

That means that temporary A is kept alive for the duration of function
foo().
So what should be correct behaviour according to c++ standard
regarding when the temporary is freed? Is the code above portable?

It looks to me like the compiler is omitting the copy construction of
one of the temporaries, per 12.8/15:
"In such cases, (...) the destruction of that object occurs at the
later of the times when the two objects would have been destroyed
without the optimization." , that is, at the end of the full-
expression foo(f1());

If the compiler did not utilize this optimization, you would see
construction and destruction of two A objects, (The first would be
destructed when exiting f1(), but the last one would still be
destructed after "foo(f1());", and the pointer p would still not point
to freed memory.

Hope this helps. (Hopefully someone will correct me if I got it wrong)

DP
 
M

Martin Bonner

Hi, sorry, messed up my previous post...

Consider the following code:

class A {
int x;
public:
A() { printf("In A()\n"); x = 5; }
~A() { printf("In ~A()\n"); }
operator int *() { printf("In int *()\n"); return &x; }

};

A f1()
{
printf("in f1()\n");
return A();
}

void foo(int *p) { printf("in foo()\n"); }

int main()
{
foo(f1()); ^Here
printf("After foo()\n");
return 0;
}

I have always thought this code is wrong because the temporary object
A would be destroyed after calling int *() operator and before
entering foo(), so the pointer p would point to freed memory.
what should be correct behaviour according to c++ standard
regarding when the temporary is freed? Is the code above portable?
Temporaries created during the evaluation of an expression, are
destroyed "at the end of the full expression". In your case, this
means the temporary lives until the semi-colon I highlight above.

The code is portable, but if feels fragile to me - it doesn't take
much of a change for the code induce references to destroyed objects.
 
D

Daniel T.

Hi, sorry, messed up my previous post...

Consider the following code:

class A {
int x;
public:
A() { printf("In A()\n"); x = 5; }
~A() { printf("In ~A()\n"); }
operator int *() { printf("In int *()\n"); return &x; }

};

A f1()
{
printf("in f1()\n");
return A();

}

void foo(int *p) { printf("in foo()\n"); }

int main()
{
foo(f1());
printf("After foo()\n");
return 0;

}

I have always thought this code is wrong because the temporary object
A would be destroyed after calling int *() operator and before
entering foo(), so the pointer p would point to freed memory. However
i complied the code in both vs2005 and gcc compilers and ran it, it
complies fine and the result in both cases is the following:

in f1()
In A()
In int *()
in foo()
In ~A()
After foo()

That means that temporary A is kept alive for the duration of
function foo().
So what should be correct behaviour according to c++ standard
regarding when the temporary is freed? Is the code above
portable?

Yes, the above code is portable. The returned temporary is alive until
the next sequence point which in this case is the semi-colon in the
line "foo(f1());" i.e. after foo returns.
 
O

Ondra Holub

Hi, sorry, messed up my previous post...

Consider the following code:

class A {
int x;
public:
A() { printf("In A()\n"); x = 5; }
~A() { printf("In ~A()\n"); }
operator int *() { printf("In int *()\n"); return &x; }

};

A f1()
{
printf("in f1()\n");
return A();

}

void foo(int *p) { printf("in foo()\n"); }

int main()
{
foo(f1());
printf("After foo()\n");
return 0;

}

I have always thought this code is wrong because the temporary object
A would be destroyed after calling int *() operator and before
entering foo(), so the pointer p would point to freed memory. However
i complied the code in both vs2005 and gcc compilers and ran it, it
complies fine and the result in both cases is the following:

in f1()
In A()
In int *()
in foo()
In ~A()
After foo()

That means that temporary A is kept alive for the duration of function
foo().
So what should be correct behaviour according to c++ standard
regarding when the temporary is freed? Is the code above portable?

{ Edits: quoted signature and clc++m banner removed. Please don't quote
extraneous material. -mod }

return A(); means, that new instance is created and its copy created
with copy constructor is returned. However if you create your own copy
constructor with some log message, you will not probably see this
message, because this copying will be optimized-out. But you can try
to create your own copy constructor declared as private - this code
shouldn't compile, becuase copy constructor is still syntactically
required.
 
T

Triple-DES

Hi, sorry, messed up my previous post...

Consider the following code:

class A {
int x;
public:
A() { printf("In A()\n"); x = 5; }
~A() { printf("In ~A()\n"); }
operator int *() { printf("In int *()\n"); return &x; }

};

A f1()
{
printf("in f1()\n");
return A();

}

void foo(int *p) { printf("in foo()\n"); }

int main()
{
foo(f1());
printf("After foo()\n");
return 0;

}

I have always thought this code is wrong because the temporary object
A would be destroyed after calling int *() operator and before
entering foo(), so the pointer p would point to freed memory. However
i complied the code in both vs2005 and gcc compilers and ran it, it
complies fine and the result in both cases is the following:

in f1()
In A()
In int *()
in foo()
In ~A()
After foo()

That means that temporary A is kept alive for the duration of function
foo().
So what should be correct behaviour according to c++ standard
regarding when the temporary is freed? Is the code above portable?

It looks to me that the copy-construction of the temporary A is elided
per 12.8/15:

"In such cases (...) the destruction of that object occurs at the
later of the times when the two objects would have been destroyed
without the optimization"

So the destruction occurs when the temporary A returned by foo()
should be destroyed, that is at the end of the full-expression
foo(f1());

Which means that if the compiler chose to not do the optimization, you
would see the destruction of two A objects, but the last one would
still be after the full-expression.

Hope this helps. (Hopefully someone will correct me if I got it all
wrong)

DP
 
T

Triple-DES

Sorry if I managed to double-post this.

Hi, sorry, messed up my previous post...

Consider the following code:

class A {
int x;
public:
A() { printf("In A()\n"); x = 5; }
~A() { printf("In ~A()\n"); }
operator int *() { printf("In int *()\n"); return &x; }

};

A f1()
{
printf("in f1()\n");
return A();

}

void foo(int *p) { printf("in foo()\n"); }

int main()
{
foo(f1());
printf("After foo()\n");
return 0;

}

I have always thought this code is wrong because the temporary object
A would be destroyed after calling int *() operator and before
entering foo(), so the pointer p would point to freed memory. However
i complied the code in both vs2005 and gcc compilers and ran it, it
complies fine and the result in both cases is the following:

in f1()
In A()
In int *()
in foo()
In ~A()
After foo()

That means that temporary A is kept alive for the duration of function
foo().
So what should be correct behaviour according to c++ standard
regarding when the temporary is freed? Is the code above portable?

It looks to me like the compiler is omitting the copy construction of
one of the temporaries, per 12.8/15:
"In such cases, (...) the destruction of that object occurs at the
later of the times when the two objects would have been destroyed
without the optimization." , that is, at the end of the full-
expression foo(f1());

If the compiler did not utilize this optimization, you would see
construction and destruction of two A objects, (The first would be
destructed when exiting f1(), but the last one would still be
destructed after "foo(f1());", and the pointer p would still not point
to freed memory.

Hope this helps. (Hopefully someone will correct me if I got it wrong)

DP
 
M

Micah Cowan

Temporaries created during the evaluation of an expression, are
destroyed "at the end of the full expression". In your case, this
means the temporary lives until the semi-colon I highlight above.

No. It's at the end of the full expression in which the temporary is
created. That would be at the semicolon _I_ highlighted.

12.2#3:

Temporary objects are destroyed as the last step in evalu- ating the
full-expression (1.9) that (lexically) contains the point where they
were created.

This is made much more explicit in #5:

A temporary bound to the returned value in a function return
statement (6.6.3) persists until the function exits.
^^^^^^^^^^^^^^^^^^^^^^^^
Your proposed full-expression obviously fails to lexically contain the point
where the temporary was created, and this case fails to meet the
criteria for exceptions to this rule. A conforming implementation, it
seems to me, would need to have destructed the temporary at the
point of the function's exit.

--
Micah J. Cowan
Programmer, musician, typesetting enthusiast, gamer...
http://micah.cowan.name/

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

Martin York

I have always thought this code is wrong because the temporary object
A would be destroyed after calling int *() operator and before
entering foo(),
No.

foo(f1());
In this case the temporary object created by calling f1() is not
destroyed until the end of the statement, which is after the call to
foo() has been completed.

I would expect the code to look like this (pre-optimization)
In F1()
In A()
In Copy A() // Copy obejct out of f1() // This can be
optimsied
In ~A() // out with this.
Finished F1() // No way to print this.
In Convert to int
In foo()
Finished foo() // No way to print this
In ~A()
 
M

Micah Cowan

Triple-DES said:
It looks to me that the copy-construction of the temporary A is elided
per 12.8/15:

"In such cases (...) the destruction of that object occurs at the
later of the times when the two objects would have been destroyed
without the optimization"

So the destruction occurs when the temporary A returned by foo()
should be destroyed, that is at the end of the full-expression
foo(f1());

Ah! So that's what I'd missed. Thanks.

(From same paragraph as above:)
in a return statement in a function with a class return type, when
the expression is the name of a non-volatile automatic object with
the same cv-unqualified type as the function return type, the copy
operation can be omitted by constructing the automatic object
directly into the function's return value
Which means that if the compiler chose to not do the optimization, you
would see the destruction of two A objects, but the last one would
still be after the full-expression.

--
Micah J. Cowan
Programmer, musician, typesetting enthusiast, gamer...
http://micah.cowan.name/

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

Micah Cowan

Martin York said:
In this case the temporary object created by calling f1() is not
destroyed until the end of the statement, which is after the call to
foo() has been completed.

I would expect the code to look like this (pre-optimization)
In F1()
In A()
In Copy A() // Copy obejct out of f1() // This can be
optimsied
In ~A() // out with this.
Finished F1() // No way to print this.
In Convert to int
In foo()
Finished foo() // No way to print this
In ~A()

(Note, of course, that this answers the question "is this code
portable": it's not. It probably doesn't make a difference, unless
your code (like this specific example) depends on the number of times
a temporary will be constructed in situations like this.)

--
Micah J. Cowan
Programmer, musician, typesetting enthusiast, gamer...
http://micah.cowan.name/

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

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top