Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Move semantics and const references

Tags:

c++

c++11

I've spend quite some time on implementing move semantics for my class but now I'm dealing with functions that use it.

Ok, so I have this object which has a lot of data on the heap: CLargeOb for which I implemented the move semantics (constructor and operator =). It is ideally used like this:

void OtherOb::Func(CLargeOb&& largeOb1, CLargeOb&& largeOb2)
{
    SomeOtherFunc(largeOb1); // use objects
    SomeOtherFunc(largeOb2); 
    m_largeOb1 = (CLargeOb&&)largeOb1; // save as members and trash the originals
    m_largeOb2 = (CLargeOb&&)largeOb2;
}

However it's not always possible to allow the objects to be moved/trashed, so I added these two functions:

void OtherOb::Func(const CLargeOb& largeOb1, CLargeOb&& largeOb2)
{
    SomeOtherFunc(largeOb1);
    SomeOtherFunc(largeOb2); 
    m_largeOb1 = largeOb1;
    m_largeOb2 = (CLargeOb&&)largeOb2;
}

void OtherOb::Func(CLargeOb&& largeOb1, const CLargeOb& largeOb2)
{
    SomeOtherFunc(largeOb1);
    SomeOtherFunc(largeOb2); 
    m_largeOb1 = (CLargeOb&&)largeOb1;
    m_largeOb2 = largeOb2;
}

Although it works, you can already guess it will become a major pain in the *ss when I have a function which takes 3 or more of these objects as parameters... Isn't there a clever way to solve this using templates or maybe 'perfect forwarding'?

like image 243
demorge Avatar asked Aug 03 '12 21:08

demorge


1 Answers

As was the case in C++03, the guideline is: if you want a copy, make it in the parameter list.

This lets the caller deal with how you get the object, you just get an object regardless:

void OtherOb::Func(CLargeOb largeOb1, CLargeOb largeOb2) 
{ 
    SomeOtherFunc(largeOb1); // use objects 
    SomeOtherFunc(largeOb2);  
    m_largeOb1 = std::move(largeOb1); // save as members and trash the originals 
    m_largeOb2 = std::move(largeOb2); // (you should use std::move, not cast)
} 

The caller:

OtherOb o;

CLargeOb x, y;
const CLargeOb z;

o.Func(x, std::move(y)); // need x for later, done with y so move it
o.Func(std::move(x), z); // done with x, necessarily copy z

This is just as efficient as several specialized overloads. Why? Because those already exist in the class as constructors. Let the compiler figure out which to call at the call site for you, it already knows what to do.

like image 199
GManNickG Avatar answered Nov 26 '22 19:11

GManNickG