use of deleted function (move constructor)
-
I've been experimenting with RVO before deciding if we should shift our coding standards to allow return values of nontrivial objects. Right now the prefered mechanism in the codbase is to pass object handle by reference parameter and reserve function return values for status code or success/failure indicators
I'm successfully seeing RVO elides in my function, as verified by examining the address of the temp object created in the method and comparing the address of the object after return from function.
Then when i specifically = delete the default move semantic methods the compiler complains of use of deleted function.
Am I incorrect in assumming that if you disable the move operations then the compilers "should" revert to expensive copy and assignment constructors or is the expectation going forward that RVO is on unless deselected with a compiler switch?
This works as expected:
subclass go() { using namespace std; std::cout << "going\n"; subclass rv(*this); std::for_each(rv.myVec.begin(), rv.myVec.end(), [](int& l) { l *= 10; } ); std::cout << "tmp-subclass @" << IsAt<subclass>(rv) << " myVec @" << IsAt<VEC>(rv.myVec) << std::endl; return rv; } subclass(const subclass& o) = default; subclass& operator=(const subclass& o)& = default; subclass(subclass&& o) = default; subclass& operator=(subclass&& o)& = default;
This causes the compile to complain:
subclass(subclass&& o) = delete; subclass& operator=(subclass&& o)& = delete;
-
What c++ standard do you use? Try it explcitly with c++11. I can't find it but I think since c++17 the compiler has to move it the same way as it has to optimize away the copy assignment in
subclass c = subclass();
-
@Kent-Dorfman
rv
in this context is an rvalue, so a move constructor is always invoked.
There's a subtle difference between deleting move constructor and not defining it at all. In the latter case compiler will generate a move constructor that simply does copy. If you explicitly delete move constructor you forbid the operation to take place in the first place. So if you don't define move constructor it will effectively roll back to the old behavior - copy, but if you do (even by deleting it), you're subscribing to existence of move semantic and control it explicitly. -
Btw. what you have here is a specific case of RVO called NRVO (Named RVO), so you return a named local variable. A classic RVO would be
return subclass(*this)
. I'm mentioning it because I've seen slight differences in how compilers treat those two. In some corner cases NRVO is not subjected to the same optimizations. There was even a bug resulting in straight wrong code gen in the early clang implementation some years ago (fixed since).Not a major difference, but something to keep in mind if you're researching the topic.
-
Thanks for the followups. So it seems langauge spec migration is toward moves regardless, but in 11 and 14 there is some ability to force behaviour, if I read the responses properly. Will try non-defined moves and see if the behaviour reverts.
I'm using gcc 8, which I think defaults to c++14.
All the syntactic candy and making c++ pythonesque is hard for an old guy who like pointers to swallow.
-
FWIW, upon further experimentation, the gnu compiler using c++14 chooses RVO regardless, as in no ovbious way to disable it. not sure I like that but considering all the other computer science missteps I'm seeing in the this generation, wouldln't make sense to rant about it anymore...just makes more sense to buy an off-grid cabin and go dark...
-
@Kent-Dorfman said:
.just makes more sense to buy an off-grid cabin and go dark...
Yeah, I thought about it too, but then I watched Into The Wild and realized I probably wouldn't last a month, so I decided to deal with the devil I know at least.