Move constructors and inheritance

送分小仙女□ 提交于 2019-12-30 05:54:11

问题


I am trying to understand the way move constructors and assignment ops work in C++11 but I'm having problems with delegating to parent classes.

The code:

class T0
{
public:
    T0() { puts("ctor 0"); }
    ~T0() { puts("dtor 0"); }
    T0(T0 const&) { puts("copy 0"); }
    T0(T0&&) { puts("move 0"); }
    T0& operator=(T0 const&) { puts("assign 0"); return *this; }
    T0& operator=(T0&&) { puts("move assign 0"); return *this; }
};

class T : public T0
{
public:
    T(): T0() { puts("ctor"); }
    ~T() { puts("dtor"); }
    T(T const& o): T0(o) { puts("copy"); }
    T(T&& o): T0(o) { puts("move"); }
    T& operator=(T const& o) { puts("assign"); return static_cast<T&>(T0::operator=(o)); }
    T& operator=(T&& o) { puts("move assign"); return static_cast<T&>(T0::operator=(o)); }
};

int main()
{
    T t = std::move(T());
    return 0;
}

However, when I compile and run under VS2012, the output indicates that the lvalue versions of the T0 members are called:

ctor 0
ctor
copy 0  <--
move    <--
dtor
dtor 0
dtor
dtor 0

A similar situation (with a slightly different test case) happens with move assignments -- the move assignment operator of T calls the "normal" assignment operator of T0.

What am I doing wrong?


回答1:


One of the more confusing things about functions taking rvalue references as parameters is that internally they treat their parameters as lvalues. This is to prevent you from moving the parameter before you mean to, but it takes some getting used to. In order to actually move the parameter, you have to call std::move (or std::forward) on it. So you need to define your move constructor as:

T(T&& o): T0(std::move(o)) { puts("move"); }

and your move assignment operator as:

T& operator=(T&& o) { puts("move assign"); return static_cast<T&>(T0::operator=(std::move(o))); }



回答2:


You're only ever calling your base class's stuff with lvalues:

void foo(int&){}  // A
void foo(int&&){} // B

void example(int&& x)
{
    // while the caller had to use an rvalue expression to pass a value for x,
    // since x now has a name in here it's an lvalue:
    foo(x); // calls variant A
}

example(std::move(myinteger)); // rvalue for us, lvalue for example

That is, you need:

T(T&& o):
T0(std::move(o)) // rvalue derived converts to rvalue base
{
    puts("move");
}

And:

T& operator=(T&& o)
{
    puts("move assign");

    T0::operator=(std::move(o)));

    return *this;
}


来源:https://stackoverflow.com/questions/15351341/move-constructors-and-inheritance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!