In the code segment above, is the move semantics stuff in DataWriter necessary? I want a guarantee that RAII on the owner Block is done just once in such a block of code:
1 2 3 4 5 6 7 8 9
int main()
{
Block block;
{
auto handle = block.GetWriteHandle();
}
return 0;
}
Can someone point me to an explanation of how a compiler is allowed to optimize this, and what assumptions a programmer can make?
> Can someone point me to an explanation of how a compiler is allowed to optimize this,
> and what assumptions a programmer can make?
Copy-elision (RVO) is mandatory in C++17, and permitted but not required in C++14.
In C++14, every mainstream compiler implements RVO when optimisations are enabled,
but every compiler may not apply the optimisation when optimisations are disabled.
error C2280: 'Block::DataWriter::DataWriter(Block::DataWriter &&)': attempting to reference a deleted function
Cannot mark the move/copy constructors as deleted. Seems it is needed to do this for completeness (in msvc14.1 at least). Not called even in debug mode though.
> What about when the function parameter is a copy?
In a return statement, if copy-elision is not possible only because the source of the copy is a function parameter, the compiler will use the move constructor (if one is available), even on an lvalue.
> Cannot mark the move/copy constructors as deleted.
For DataWriter GetWriteHandle() { return DataWriter(this); }
It is only C++17 that does not require that there must be an accessible copy/move constructor.
(This optimisation is mandated by the standard; there is no copy/move because every implementation is required to elide the copy.)
In earlier versions of C++, even if the optimisation does take place, and no copy/move constructor is actually called, there must still be an accessible copy/move constructor. (ie. the program must be well-formed, irrespective of whether an implementation performs this optimisation or not.)