Compiler error : Only Copy elision is wanted, but move constructor seems to be required (by compiler)


Compiler error : Only Copy elision is wanted, but move constructor seems to be required (by compiler)



Attempting to compile to this code give a compiler error with 'newer' compilers (im guessing: that support move constructors). Something along the lines of "attempting to call deleted function". Tried with gcc 8.1, MSVC 19.10 and clang 6.0.0


#include <string>
#include <iostream>
#include <sstream>


class A : public std::stringstream {
public:
A(std::string str) : str_(str) {
}
//A(A&&);

~A() {
std::cout << str_;
}
std::string str_;
};


A make_A() {
return A("hello");
}

int test(int num) {
A test = make_A();
}



The 'A' class is a simply 'exploit' of copy-elision (or RVO - Return Value Optimization) and the fact that this doesn't invoke the custom destructor either.



Surprisingly, commenting in the declaration of A's move constructor, makes the code both compile AND link. So it could maybe look like the compiler first 'thinks' it needs the function - but later figures out the copy elision is possible.



This was the intended the behavior - that there should be no need for either calling.



Putting in the declaration without an implementation is no longer good practice.
So can anyone give an explanation why this is not allowed with the standard(assuming it is not) ? I am also looking for a better solution.



Update: The code is used for a logger class that, when called, returns a temporary stringstream which when gets destroyed logs whatever is in the string buffer. The logger also has some internals of extra info of where to log, severity, etc.



Exact compile error with gcc 7.3:


<source>: In function 'A make_A()':

<source>:21:19: error: use of deleted function 'A::A(const A&)'

return A("hello");

^

<source>:7:7: note: 'A::A(const A&)' is implicitly deleted because the default definition would be ill-formed:

class A : public std::stringstream {

^

<source>:7:7: error: use of deleted function 'std::__cxx11::basic_stringstream<_CharT, _Traits,
_Alloc>::basic_stringstream(const std::__cxx11::basic_stringstream<_CharT, _Traits, _Alloc>&) [with
_CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]'

In file included from <source>:4:0:

/opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/sstream:734:7: note: declared here

basic_stringstream(const basic_stringstream&) = delete;

^~~~~~~~~~~~~~~~~~

<source>:7:7: error: use of deleted function 'std::basic_ios<_CharT,
_Traits>::basic_ios(const std::basic_ios<_CharT, _Traits>&) [with _CharT = char; _Traits = std::char_traits<char>]'

class A : public std::stringstream {

^

In file included from /opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/ios:44:0,

from /opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/ostream:38,

from /opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/iostream:39,

from <source>:3:

/opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/bits/basic_ios.h:475:7: note: declared here

basic_ios(const basic_ios&) = delete;

^~~~~~~~~

<source>: In function 'int test(int)':

<source>:25:21: error: use of deleted function 'A::A(const A&)'

A test = make_A();

^

Compiler returned: 1





Are you sure B(const B&&) is correct? It should be B(B&&) and if it is it compiles just fine: godbolt.org/g/4PEFuP
– NathanOliver
Jun 28 at 13:07


B(const B&&)


B(B&&)





B(const B&&) makes no sense, most of the time move steals the guts of the other objects, but you cant do that if its const.
– Borgleader
Jun 28 at 13:13


B(const B&&)





"Putting in the declaration without an implementation is no longer good practice.". Have you considered using the explicitly defaulted move constructor? That is... A(A&&) = default; - note I removed const
– Frank Boyne
Jun 28 at 18:40



A(A&&) = default;


const





Maybe you can better explain what are you trying to achieve?
– Volt
Jun 28 at 18:55





You might consider using C++17, where RVO is in some situations mandatory instead of just allowed, removing the requirement for move-constructibility. Anyway, please add which Standard Version you compile for.
– Deduplicator
2 days ago





1 Answer
1



After comment by Deduplicator, it became clear c++17 standard was not used in the compile tests. Moreover, the "guarenteed copy elision" feature first made it into MSVC from version 19.30 where as MSVC 19.10 was used in the compile tests.



So using latest standard (c++17) and compilers solves the issue.
For MSVC at least MSVC 19.30. For GCC version 7, and for CLANG version 4.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Comments

Popular posts from this blog

paramiko-expect timeout is happening after executing the command

Export result set on Dbeaver to CSV

Opening a url is failing in Swift