Why would const-ness of a local variable inhibit move semantics for the returned value?

瘦欲@ 提交于 2019-12-04 23:07:50

A program is ill-formed if the copy/move constructor [...] for an object is implicitly odr-used and the special member function is not accessible

-- n3485 C++ draft standard [class.copy]/30

I suspect your problem is with MSVC 2012, and not with C++11.

This code, even without calling it, is not legal C++11:

struct STest {
  STest(STest const&) = delete
  STest(STest && test) : m_n( std::move(test.m_n) ) {}
  explicit STest(int n) : m_n(n) {}
  int m_n;
};

STest FuncUsingConst(int n) {
  STest const a(n);
  return a;
}

because there is no legal way to turn a into a return value. While the return can be elided, eliding the return value does not remove the requirement that the copy constructor exist.

If MSVC2012 is allowing FuncUsingConst to compile, it is doing so in violation of the C++11 standard.

Andy Prowl

I like making local variables const where appropriate. It helps me clean up my train of thought and clearly structure an algorithm.

That is indeed a good practice. Use const wherever you can. Here, however, you cannot (if you expect your const object to be moved from).

The fact that you declare a const object inside your function is a promise that your object's state won't ever be altered as long as the object is alive - in other words, never before its destructor is invoked. Not even immediately before its destructor is invoked. As long as it is alive, the state of a const object shall not change.

However, here you are somehow expecting this object to be moved from right before it gets destroyed by falling out of scope, and moving is altering state. You cannot move from a const object - not even if you are not going to use that object anymore.

What you can do, however, is to create a non-const object and access it in your function only through a reference to const bound to that object:

STest FuncUsingConst(int n) {
    STest object_not_to_be_touched_if_not_through_reference(n);
    STest const& a = object_not_to_be_touched_if_not_through_reference;

    // Now work only with a

    return object_not_to_be_touched_if_not_through_reference;
}

With a bit of discipline, you can easily enforce the semantics that the function should not modify that object after its creation - except for being allowed to move from it when returning.

UPDATE:

As suggested by balki in the comments, another possibility would be to bind a constant reference to a non-const temporary object (whose lifetime would be prolonged as per § 12.2/5), and perform a const_cast when returning it:

STest FuncUsingConst(int n) {
    STest const& a = STest();

    // Now work only with a

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