Passing Temporaries to perform non const operations

J

joecook

Altering a temporary is perfectly legal, for example:

std::vector<int> vec(40);
std::vector<int>(4).swap(vec); //legal.

I am trying to get this same functionality, but within an assignment
operator, but can't seem to find a good way to bind the temporary.

For example:

class Foo;
int main()
{
Foo f;
f = Foo(20);
}

#include <vector>
class Foo
{
public:
Foo(int size=0) { m_data.resize(size);}

// PROBLEM HERE. The temporary can't be bound to a reference to non-
const
// But if this were 'const reference', the swap function could not
be called using it.
void operator=(Foo& foo)
{
m_data.swap(foo.m_data);
}
std::vector<int> m_data;
};

The only work-around I could think of was this ugly code:
void operator=(const Foo& foo)
{
std::vector<T>* tmpVec = const_cast<std::vector<T>*>(foo.m_data);
tmpVec->swap(m_data);
}

Any better suggestions?
Thanks,
Joe
 
V

Victor Bazarov

Altering a temporary is perfectly legal, for example:

std::vector<int> vec(40);
std::vector<int>(4).swap(vec); //legal.

I am trying to get this same functionality, but within an assignment
operator, but can't seem to find a good way to bind the temporary.

You've run into the same problem many of C++ programmers had over the
past several years. You need "move semantics". If you'd like to know
more about those, look them up.

Currently the work is under way to make "move semantics" simpler in the
language itself, with the help of rvalue references.
For example:

class Foo;
int main()
{
Foo f;
f = Foo(20);
}

#include <vector>
class Foo
{
public:
Foo(int size=0) { m_data.resize(size);}

// PROBLEM HERE. The temporary can't be bound to a reference to non-
const
// But if this were 'const reference', the swap function could not
be called using it.
void operator=(Foo& foo)
{
m_data.swap(foo.m_data);
}
std::vector<int> m_data;
};

The only work-around I could think of was this ugly code:
void operator=(const Foo& foo)
{
std::vector<T>* tmpVec = const_cast<std::vector<T>*>(foo.m_data);
tmpVec->swap(m_data);
}

Any better suggestions?

Wait a couple of years when your compiler implements the rvalue
references...

Check out the existing solutions for 'move semantics'. Andrei
Alexandrescu's work comes to mind (the 'MOJO' library).

V
 
B

Bart van Ingen Schenau

Altering a temporary is perfectly legal, for example:

std::vector<int> vec(40);
std::vector<int>(4).swap(vec);   //legal.

I am trying to get this same functionality, but within an assignment
operator, but can't seem to find a good way to bind the temporary.

For example:

class Foo;
int main()
{
 Foo f;
 f = Foo(20);

}

#include <vector>
class Foo
{
public:
  Foo(int size=0) { m_data.resize(size);}

  // PROBLEM HERE.  The temporary can't be bound to a reference to non-
const
  // But if this were 'const reference', the swap function could not
be called using it.
  void operator=(Foo& foo)
  {
    m_data.swap(foo.m_data);
  }
  std::vector<int> m_data;

};

The only work-around I could think of was this ugly code:
void operator=(const Foo& foo)
{
  std::vector<T>* tmpVec = const_cast<std::vector<T>*>(foo.m_data);
  tmpVec->swap(m_data);

}

Any better suggestions?

As long as move semantics are not yet available, your best option is
to use pass-by-value and hope the compiler optimises out any redundant
temporaries.

void operator=(Foo foo)
{
m_data.swap(foo.m_data);
}
Thanks,
Joe

Bart v Ingen Schenau
 
J

James Kanze

This isn't legal. m_data isn't a pointer, and can't be
converted to one. Perhaps you meant to use '&', instead of '*',
in the above.
As long as move semantics are not yet available, your best
option is to use pass-by-value and hope the compiler optimises
out any redundant temporaries.
void operator=(Foo foo)
{
m_data.swap(foo.m_data);
}

But that doesn't have the same semantics. For some reason
(obfuscation?), he wants the assignment operator to modify the
object on the right hand side of the assignment as well.
 
V

Victor Bazarov

James said:
[..]
But that doesn't have the same semantics. For some reason
(obfuscation?), he wants the assignment operator to modify the
object on the right hand side of the assignment as well.

I am guessing you're not up to speed on move semantics. Specifically
for that purpose the language in its next incarnation will have the
"move assignment operator" (in addition to a copy assignment operator).
Read up on it. Hint: the reason is not obfuscation, it's real, it has
to do with performance.

V
 
S

SG

I am guessing you're not up to speed on move semantics.  Specifically
for that purpose the language in its next incarnation will have the
"move assignment operator" (in addition to a copy assignment operator).

There's no special move assignment operator. It's still an assignment
('='). But you can declare/overload this function for different
parameter types -- including non-const rvalue references. But I guess
this is why you put "move assignment operator" in quotes.

Anyhow ...

In many cases you probably won't need overloaded operator= functions
like
T& T::eek:perator=(T const&);
T& T::eek:perator=(T &&);

In case moving is cheap -- it can be cheap for many T with sizeof(T)
being small -- I'd still use the copy-and-swap trick. In C++03 the
copy might be elided by a compiler. In addition, C++0x will guarantee
that an rvalue argument to this function won't be copied if it has a
move-constructor.

T::T(T&&); // move constructor
T& T::eek:perator=(T); // copy & swap


Cheers!
SG
 
V

Victor Bazarov

SG said:
There's no special move assignment operator.

No? Well, I searched through the new Standard draft, and found several
places where "move assignment" is used. A "move assignment operator" is
explicitly referenced in [vector.modifiers], I can't think it's by mistake.
> It's still an assignment
('='). But you can declare/overload this function for different
parameter types -- including non-const rvalue references. But I guess
this is why you put "move assignment operator" in quotes.

[..]

I put it in quotes to encourage googling for it

V
 
J

James Kanze

James said:
[..]
But that doesn't have the same semantics. For some reason
(obfuscation?), he wants the assignment operator to modify
the object on the right hand side of the assignment as well.
I am guessing you're not up to speed on move semantics.

Not really, but I do presume that it won't change the semantics
of existing code. And his implementation of operator= currently
has well defined semantics in C++.
Specifically for that purpose the language in its next
incarnation will have the "move assignment operator" (in
addition to a copy assignment operator).
Read up on it. Hint: the reason is not obfuscation, it's
real, it has to do with performance.

It's not just performance, I think. But it doesn't do what his
operator= does.
 
S

SG

There is: it's defined in the standard as "as assignment operator which
accepts only an revalue argument of the type being assigned".

I actually didn't find the definition. The expression "copy
assignment operator" is used a lot. I would count §12.8/9
[class.copy] as a definition for it. The expression "move assignment
operator" is only used once (§23) and doesn't qualify as definition.
Maybe I'm not up-to-date. I only checked N2800.pdf just now.

From a practical point of view it makes sense to use these expressions
to differentiate between operator= functions that either copy or move
from their argument. It gets easier to talk about it, then.

Until now, by "assignment operator" I was referring to the sign '='
instead of a function. §5.17 [expr.ass] seems to suggest the same.
Of course, there is no special sign related specifically to move-
assignments.

I'm totally fine with the expressions "move assignment" and "copy
assignment", though.

Cheers!
SG
 
V

Victor Bazarov

James said:
James said:
[..]
But that doesn't have the same semantics. For some reason
(obfuscation?), he wants the assignment operator to modify
the object on the right hand side of the assignment as well.
I am guessing you're not up to speed on move semantics.

Not really, but I do presume that it won't change the semantics
of existing code.

Of course not. The changes to the library are coming at the same time
the language is extended, and everyone will be able to take advantage of
it relatively easily. IOW, behind the scenes, if you do

myvector = function_returning_a_vector_by_value(args);

it will suddenly be more efficient.
> And his implementation of operator= currently
has well defined semantics in C++.

And that isn't going to changes, of course. However, with overloading
the assignment operator for modifiable rvalue reference, you can define
a special handling when the right-hand side of the assignment is a
temporary object. It's really fascinating what effect it is going to have.

V
 

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

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,708
Latest member
SherleneF1

Latest Threads

Top