Check if an argument is temporary

K

Klaas Vantournhout

Hi all,

I was wondering if it is possible if you can check in a function if one
of the arguments is temporary.

What I mean is the following. A is a class, foo is a function returning
a class and bar is a function using A is an argument returning something
else

class A;
A foo(void);
int bar(const A&);

int main(void) {
std::cout << bar(foo());
return 0;
}

In the above piece of code, the object returned by foo is temporary and
destroyed after bar is finished with it.

The question is, is it possible to distinguish in bar if its argument is
such a temporary object or not?

Regards
Klaas
 
D

Daniel T.

Klaas Vantournhout said:
I was wondering if it is possible if you can check in a function if one
of the arguments is temporary.

What I mean is the following. A is a class, foo is a function returning
a class and bar is a function using A is an argument returning something
else

class A;
A foo(void);
int bar(const A&);

int main(void) {
std::cout << bar(foo());
return 0;
}

In the above piece of code, the object returned by foo is temporary and
destroyed after bar is finished with it.

The question is, is it possible to distinguish in bar if its argument is
such a temporary object or not?

Not portably. If you know enough about the system you are on, you can
tell from the address if it is in the heap or on the stack, but that's
about it.

An obvious solution would be to have a separate argument in 'bar()' to
tell the function if the object passed in is a temp or not. :)
 
J

James Kanze

Not portably. If you know enough about the system you are on, you can
tell from the address if it is in the heap or on the stack, but that's
about it.

That wouldn't help, since local variables are also on the stack.
An obvious solution would be to have a separate argument in
'bar()' to tell the function if the object passed in is a temp
or not. :)

Overloading on a const reference and a non-const reference might
be sufficient. A const variable will still bind to the const
reference, like a temporary, but a non-const variable will bind
to the non-const reference.

The real question is why the OP wants to know. There's likely a
solution to his real problem which doesn't require such
knowledge.
 
K

Klaas Vantournhout

James said:
The real question is why the OP wants to know. There's likely a
solution to his real problem which doesn't require such
knowledge.

Hmm okay this is what I had in mind.

Assume you have a class array

class array {
public:
array(int N) : n(N) {
if (n) a = new double[N];
else a = NULL;
}

~array(void) { delete [] a; }

array operator=(const array &A) {
if (n != A.n) { delete [] a;
a = new double [A.n]; }
for (register int i=N-1; i >= 0; --i)
a = A.a;

return *this;
}
private
double *a;
int n;
}

Assume now we have the function
array foo(void);
which creates an enormous array

Then the following operation

array B;
B = foo();

Creates a tremendous amount of overhead.

A temporary array is created in foo(), this array is passed to operator=
and there each element of foo is copied to B.

However, it would be useful if operator= could notice if the object is
temporary.
Because then we could write

if (temporary) {
a = A.a; A.a = NULL;
}

When this happens, foo gets destroyed after operator=, but it is only a
NULL pointer, the real date is still there and not delete with ~array(void);

Of course I see a problem here there I defined operator=(const array &),
which means that I can not change A.a its value!

The simple solution would obviously be redefining
array foo(void)
to
void foo(array &)
but this is unfortunately not an option here.


Of course the above would not be a problem if optimization flags of
compilers check if content a memory address is just moved to an other
address. I don't know any assembly here, but what I mean is the
following. Assume address a is filled by function1 and contains
temporary data, and this data is placed by function2 in address b. Then
I don't know if optimization flags see this, and immediately store the
data of function1 in address b, instead of going around over temporary a.


Regards
Klaas
 
G

gpderetta

James said:
The real question is why the OP wants to know. There's likely a
solution to his real problem which doesn't require such
knowledge.

Hmm okay this is what I had in mind.

Assume you have a class array

class array {
public:
array(int N) : n(N) {
if (n) a = new double[N];
else a = NULL;
}

~array(void) { delete [] a; }

array operator=(const array &A) {
if (n != A.n) { delete [] a;
a = new double [A.n]; }
for (register int i=N-1; i >= 0; --i)
a = A.a;

return *this;
}
private
double *a;
int n;

}

Assume now we have the function
array foo(void);
which creates an enormous array

Then the following operation

array B;
B = foo();

Creates a tremendous amount of overhead.

A temporary array is created in foo(), this array is passed to operator=
and there each element of foo is copied to B.

However, it would be useful if operator= could notice if the object is
temporary.
Because then we could write

if (temporary) {
a = A.a; A.a = NULL;

}

When this happens, foo gets destroyed after operator=, but it is only a
NULL pointer, the real date is still there and not delete with ~array(void);


Make A::eek:perator= take the argument by Value instead of reference,
then swap 'this' and the argument:

struct A {
A(...) { allocate-and-initialize-p }

A(const A& rhs) { allocate-p-and-intialize-from-rhs }

A& operator=(A x) {
swap(*this, x);
return *this;
}

firend void swap(A& lsh, A& rhs) {
std::swap(lsh.p, rhs.p);
}
private:
whatever * p
};

(you do not really need a friend swap, you could directly swap or
pilfer the pointer inside operator=, but swap is generally useful).
If the argument of operator= is an lvalue, it will perform a copy (and
you would need to do it anyway), which will swaped into 'this' without
making .
If it is a temporary, like in this case:

A foo();
...
A x;
x = foo();+

the compiler is free (and any decent complier will actually do so) to
construct the result of foo directly in the argument slot of
A::eek:perator=, skipping any intermediate temporary. Also note that an
operator= implemented in term of swap has the nice side effect of
being trivially exception safe (your is not, consider what would
happen if 'operator new' throws), safe even in face of self assignment
and does eliminate any code duplicated with the copy constructor.

HTH,

Giovanni P. Deretta
 
G

Guest

James said:
The real question is why the OP wants to know. There's likely a
solution to his real problem which doesn't require such
knowledge.

Hmm okay this is what I had in mind.

Assume you have a class array

class array {
public:
array(int N) : n(N) {
if (n) a = new double[N];
else a = NULL;
}

~array(void) { delete [] a; }

array operator=(const array &A) {
if (n != A.n) { delete [] a;
a = new double [A.n]; }
for (register int i=N-1; i >= 0; --i)
a = A.a;

return *this;
}
private
double *a;
int n;

}

Assume now we have the function
array foo(void);
which creates an enormous array

Then the following operation

array B;
B = foo();

Creates a tremendous amount of overhead.

A temporary array is created in foo(), this array is passed to operator=
and there each element of foo is copied to B.

However, it would be useful if operator= could notice if the object is
temporary.
Because then we could write

if (temporary) {
a = A.a; A.a = NULL;

}

When this happens, foo gets destroyed after operator=, but it is only a
NULL pointer, the real date is still there and not delete with ~array(void);


Make A::eek:perator= take the argument by Value instead of reference,
then swap 'this' and the argument:


So you remove one copy and create a new. By taking the argument by value
a copy must be made so nothing is won.

The solution to the problem is called R-value References or Move
Semantics and will be part of the next version of the standard. Using
this you will be able to write move-constructors which transfers
ownership from the temporary to the new object.
 
D

Daniel T.

Erik Wikström said:
gpderetta wrote:

So you remove one copy and create a new. By taking the argument by
value a copy must be made so nothing is won.

Seems to me you missed gpderetta's comment below
If [the parameter] is a temporary... the compiler is free (and
any decent complier will actually do so) to construct the result
of foo directly in the argument slot of A::eek:perator=, skipping
any intermediate temporary.
 
G

Guest

James Kanze wrote:
The real question is why the OP wants to know. There's likely a
solution to his real problem which doesn't require such
knowledge.

Hmm okay this is what I had in mind.

Assume you have a class array

class array {
public:
array(int N) : n(N) {
if (n) a = new double[N];
else a = NULL;
}

~array(void) { delete [] a; }

array operator=(const array &A) {
if (n != A.n) { delete [] a;
a = new double [A.n]; }
for (register int i=N-1; i >= 0; --i)
a = A.a;

return *this;
}
private
double *a;
int n;

}

Assume now we have the function
array foo(void);
which creates an enormous array

Then the following operation

array B;
B = foo();

Creates a tremendous amount of overhead.

A temporary array is created in foo(), this array is passed to operator=
and there each element of foo is copied to B.

However, it would be useful if operator= could notice if the object is
temporary.
Because then we could write

if (temporary) {
a = A.a; A.a = NULL;

}

When this happens, foo gets destroyed after operator=, but it is only a
NULL pointer, the real date is still there and not delete with ~array(void);


Make A::eek:perator= take the argument by Value instead of reference,
then swap 'this' and the argument:


So you remove one copy and create a new. By taking the argument by value
a copy must be made so nothing is won.

The solution to the problem is called R-value References or Move
Semantics and will be part of the next version of the standard. Using
this you will be able to write move-constructors which transfers
ownership from the temporary to the new object.


It is an optimisation that the compiler is allowed to, but not required
to do. Also, there are situations where it is not possible. Consider the
following:

class Foo {};

Foo bar(int i)
{
Foo f1, f2;
if (i == 1)
return f1;
return f2;
}

int main()
{
Foo f;
f = bar(1);
}

In this case I can not make my compiler omit the copy-construction. It
is because of situations like this (among other things) that move
semantics were added.
 
J

James Kanze

Hmm okay this is what I had in mind.
Assume you have a class array
class array {
public:
array(int N) : n(N) {
if (n) a = new double[N];
else a = NULL;
}
~array(void) { delete [] a; }
array operator=(const array &A) {
if (n != A.n) { delete [] a;
a = new double [A.n]; }
for (register int i=N-1; i >= 0; --i)
a = A.a;

return *this;
}
private
double *a;
int n;
}

Assume now we have the function
array foo(void);
which creates an enormous array
Then the following operation
array B;
B = foo();
Creates a tremendous amount of overhead.

True. There are work-arounds, but it is an important enough
problem to have been addressed by the standards committee, which
are adding "move" semantics to the language. In the meantime,
there are several possible work-arounds (all rather a bother to
program): the easiest to implement, at least in a single
threaded environment, is probably some form of copy on write.
Alternatively, you use "helper objects" foo() doesn't do
anything itself but return a helper object; an assignment
operator is declared to accept the helper object, and the actual
logic in foo is moved into the helper object. Something like:

class Array
{
public:
// ...
template< typename Helper >
Array& operator=( Helper const& h )
{
h.getData( this ) ; // Modify data here...
return *this ;
}
} ;

This allows foo (or rather, the code which used to be in foo) to
modify existing data, rather than having to create a new
instance.
A temporary array is created in foo(), this array is passed to operator=
and there each element of foo is copied to B.
However, it would be useful if operator= could notice if the object is
temporary.
Because then we could write
if (temporary) {
a = A.a; A.a = NULL;
}

And leak the memory which a used to point to:). The classical
idiom here is swap, so that the destructor of the temporary
takes care of releasing any resources originally used by the
target.
 
G

gpderetta

James Kanze wrote:
The real question is why the OP wants to know. There's likely a
solution to his real problem which doesn't require such
knowledge.
Hmm okay this is what I had in mind.
Assume you have a class array
class array {
public:
array(int N) : n(N) {
if (n) a = new double[N];
else a = NULL;
}
~array(void) { delete [] a; }
array operator=(const array &A) {
if (n != A.n) { delete [] a;
a = new double [A.n]; }
for (register int i=N-1; i >= 0; --i)
a = A.a;
return *this;
}
private
double *a;
int n;
}
Assume now we have the function
array foo(void);
which creates an enormous array
Then the following operation
array B;
B = foo();
Creates a tremendous amount of overhead.
A temporary array is created in foo(), this array is passed to operator=
and there each element of foo is copied to B.
However, it would be useful if operator= could notice if the object is
temporary.
Because then we could write
if (temporary) {
a = A.a; A.a = NULL;
}
When this happens, foo gets destroyed after operator=, but it is only a
NULL pointer, the real date is still there and not delete with ~array(void);

Make A::eek:perator= take the argument by Value instead of reference,
then swap 'this' and the argument:

So you remove one copy and create a new. By taking the argument by value
a copy must be made so nothing is won.


It is the asignment operator, so, yes, you need to do at least one
copy. Consider
the canonical exception safe operator=:

A& A::eek:perator=(A const& rhs) {
A tmp(rhs);
using std::swap;
swap(*this, rhs);
return *this;
}

You have to do a copy anyway, but if you capture by value instead of
reference,
you save a copy if the argument was an rvalue anyway.
The solution to the problem is called R-value References or Move
Semantics and will be part of the next version of the standard. Using
this you will be able to write move-constructors which transfers
ownership from the temporary to the new object.

Sure, R-Value references are a wellcome addition. But a take-by-value
operator= can
implemented *now* without language changes. And anyway, if you are
willing to do some
scafold work, move semantics are implementable in C++03 without
language extensions, see
the works of Alexandrescu and Abrahams. (the take take-by-value
operator= is an
useful subset of that).
 
G

gpderetta

class Foo {};

Foo bar(int i)
{
Foo f1, f2;
if (i == 1)
return f1;
return f2;

}

int main()
{
Foo f;
f = bar(1);

}

In this case I can not make my compiler omit the copy-construction. It
is because of situations like this (among other things) that move
semantics were added.

If operator= has signature Foo& Foo::eek:perator=(const Foo&) you need to
do two copies of Foo:
one at return time (when you copy f1 or f2 to the return temporary)
and one inside
operator=. If you take by value, the temporary becomes directly the
argument of the operator= and you
can swap it with 'this' saving a copy.

Whether bar if NRV optimizable or not has nothing to do with
the ability of the compiler to omit the temporary used to copy-
construct a named object
(the argument to operator=). They are two distinct optimizations, and,
in your example, each can
save a copy.

Also, while NRVO is not always applicable (as you have shown),
the latter optimization can be done pratically always (and AFAIK
pratically all compilers do it).

BTW, if you rely on those two optimizations, you can force a move with
this simple function:

template<typename T>
T to_rvalue(T& x) {
T result;
using std::swap;
swap(result, x);
return result;
}

...
some_type x;
some_type y = to_rvalue(x); // move
some_type z;
z = to_rvalue(y); // move

to_rvalue assumes that T is default constructible and swappable. Also
it will only useful is swap can be implemented efficiently
(which is true for all movable objects)
 
J

James Kanze

[...]
It is the asignment operator, so, yes, you need to do at least one
copy.

Not necessarily. If the argument to the operator= is a value,
rather than a reference, the compiler can use RVO or NRVO when
it constructs it; roughly speaking, the array that is being
constructed in foo() will be the one that the operator= sees.
Consider
the canonical exception safe operator=:
A& A::eek:perator=(A const& rhs) {
A tmp(rhs);
using std::swap;
swap(*this, rhs);
return *this;
}
You have to do a copy anyway, but if you capture by value
instead of reference, you save a copy if the argument was an
rvalue anyway.

Generally, I prefer this form, simply because the reference
argument is really what is expected, and seeing something else
on an operator= may cause (a little) confusion. If the
profiler says that the copy is a bottleneck, however, it's not
something so important that I'd let it stop me from using the
value. In such cases, it is a definite improvement in
performance; if the compiler correctly implements RVO and NRVO
(and many do), then you may easily end up without any copies
what so ever; a new object is constructed with its new values in
the function, and that object is swapped with the existing one
in the operator=.

There are doubtlessly other solutions, based on helper classes,
which can also be used. They are significantly more complex,
but can be made to avoid the copy even if the compiler doesn't
implement NRVO or RVO.
 
T

terminator

Klaas said:
James said:
The real question is why the OP wants to know. There's likely a
solution to his real problem which doesn't require such
knowledge.
Hmm okay this is what I had in mind.
Assume you have a class array
class array {
public:
array(int N) : n(N) {
if (n) a = new double[N];
else a = NULL;
}
~array(void) { delete [] a; }
array operator=(const array &A) {
if (n != A.n) { delete [] a;
a = new double [A.n]; }
for (register int i=N-1; i >= 0; --i)
a = A.a;

return *this;
}
private
double *a;
int n;
}
Assume now we have the function
array foo(void);
which creates an enormous array
Then the following operation
array B;
B = foo();
Creates a tremendous amount of overhead.

True. There are work-arounds, but it is an important enough
problem to have been addressed by the standards committee, which
are adding "move" semantics to the language. In the meantime,
there are several possible work-arounds (all rather a bother to
program): the easiest to implement, at least in a single
threaded environment, is probably some form of copy on write.
Alternatively, you use "helper objects" foo() doesn't do
anything itself but return a helper object; an assignment
operator is declared to accept the helper object, and the actual
logic in foo is moved into the helper object. Something like:

class Array
{
public:
// ...
template< typename Helper >
Array& operator=( Helper const& h )
{
h.getData( this ) ; // Modify data here...
return *this ;
}
} ;

This allows foo (or rather, the code which used to be in foo) to
modify existing data, rather than having to create a new
instance.
A temporary array is created in foo(), this array is passed to operator=
and there each element of foo is copied to B.
However, it would be useful if operator= could notice if the object is
temporary.
Because then we could write
if (temporary) {
a = A.a; A.a = NULL;
}

And leak the memory which a used to point to:). The classical
idiom here is swap, so that the destructor of the temporary
takes care of releasing any resources originally used by the
target.


1). I think the proposed syntax for rvalue ref (type&&) is inefficient
in that you can not specify the '*this' object of an instance-
member_function as temporary.I mean you can not specialize member
functions based on r/l-valueness of the object the way you do for
const/volatility.Plz see this:

http://groups.google.com/group/comp.std.c++/browse_thread/thread/6fdae8f5a0eb863f

2). Let us assume that special syntax is provided for r-value
refrences .take the following:

#define lvalue(type) type&
#define rvalue(type) /*equivalent to rvalue ref syntax*/
class foo{
public:
foo();
foo (const lvalue(foo) );
foo (const rvalue(foo) );
};

foo bar(){
foo result;//bar always returns result.
/////...
return result;
};

class ret_type some_fn(params){
foo obj(bar());
////...
}


If RVO/NRVO is switched of a call to 'some_fn' will result to the
following sequence:

call bar
default construct bar::result
...
copy construct temporary from bar::result
destruct result
move construct some_fn::eek:bj from temporay
destruct temporary
....

as you can see the unnecessary copy from bar::result to temporary and
destruction of result can not be removed via rvalue ref.One can
replace the extra copy with move but the extra construction and
destruction is not removed:

foo bar(){
foo result;//bar always returns result.
...
return (rvalue(foo))result;//cast to rvalue
};

the senario changes to:

call bar
default construct bar::result
...
move construct temporary from bar::result
destruct result
move construct some_fn::eek:bj from temporay
destruct temporary
....

but the contruction of temporary from bar::result and destruction of
result still perform.IMHO it is quite simple to calcuulate the address
of temporary at the beginning of bar ,and since bar is always
returning the same object ,the compiler must 'union' the temporary
with 'result' and avoid constructing the temporary from result .IMHO
this special case should become part of standard behavoir rather than
an optimization choice.Another option would be:

http://groups.google.com/group/comp.std.c++/browse_thread/thread/bd52daa8ac2e51f1

regards,
FM.
 
G

gpderetta

On 2007-10-29 12:27, gpderetta wrote:
[...]
Make A::eek:perator= take the argument by Value instead of
reference, then swap 'this' and the argument:
So you remove one copy and create a new. By taking the
argument by value a copy must be made so nothing is won.
It is the asignment operator, so, yes, you need to do at least one
copy.

Not necessarily. If the argument to the operator= is a value,
rather than a reference, the compiler can use RVO or NRVO when
it constructs it; roughly speaking, the array that is being
constructed in foo() will be the one that the operator= sees.

Yes, you are right. What should have said, is that you need to invoke
an expensive
constructor at least once, wheter inside a function which does NRVO,
or initializing the
argument of a
Consider
the canonical exception safe operator=:
A& A::eek:perator=(A const& rhs) {
A tmp(rhs);
using std::swap;
swap(*this, rhs);
return *this;
}
You have to do a copy anyway, but if you capture by value
instead of reference, you save a copy if the argument was an
rvalue anyway.
[...]
If the
profiler says that the copy is a bottleneck, however, it's not
something so important that I'd let it stop me from using the
value. In such cases, it is a definite improvement in
performance; if the compiler correctly implements RVO and NRVO
(and many do), then you may easily end up without any copies
what so ever; a new object is constructed with its new values in
the function, and that object is swapped with the existing one
in the operator=.

The reason I often do not bother with this optimization is that the
standard library I usually use doesn't do it for standard containers,
so I have the habit to never (re)assign potentially heavy objects.
I usually do a a copy initialization or use a swap member:

A foo();
....
A x;
....
foo().swap(x);
There are doubtlessly other solutions, based on helper classes,
which can also be used. They are significantly more complex,
but can be made to avoid the copy even if the compiler doesn't
implement NRVO or RVO.

Yes, you can implement move sematics in C++03, but it is a bit
involved, and where would you need them the most (inside std
containers),
they can't be used (unless you reimplement the containers of course).
Is there any relatively modern compiler which doesn't do NRVO or RVO
(in most reasonable cases at least) or doesn't
eliminate temporaries used in copy initialization?
 
P

Pete Becker

1). I think the proposed syntax for rvalue ref (type&&) is inefficient
in that you can not specify the '*this' object of an instance-
member_function as temporary.I mean you can not specialize member
functions based on r/l-valueness of the object the way you do for
const/volatility.

You can't use that notation to overload on the qualifiers for the
object, because it applies to ordinary arguments. But as of the latest
draft C++0x standard (N2461), you can use & or && to overload member
functions in the same way you use const or volatile.
 
T

terminator

You can't use that notation to overload on the qualifiers for the
object, because it applies to ordinary arguments. But as of the latest
draft C++0x standard (N2461), you can use & or && to overload member
functions in the same way you use const or volatile.

On intrinsic-type temporaries you cannot invoke assignment or inc/
decrement operators .What is the logic on being unable to treat
'*this' based on its r/l-value state?
IMHO a more descriptive syntax for r-values can facilitate r/l-value
specialization on '*this'.

regards,
FM
 
K

Klaas Vantournhout

Hi all,

Thanks for all your extensive replies. As I see it, it is a rather well
known problem of all the copying and it shows that there is not really a
direct solution in standard c++.

I have implemented a swap option in it, which basically is the fastest
way for my problem.

Thanks for your help all

Klaas
 

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,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top