c++gccvisual-c++rvo

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".

It turns out that compiling with gcc 8.1 and clang 6.0.0 when c++17 is enabled (thought to be due to the feature "guarenteed copy elision") is error free. However, it also became clear that with MSVC 19.14 (also with c++17 enabled) it fails, even though it should have that feature(came in 19.13). So is this just a bug with MSVC, is it allowed to do that, or is it another feature altogether ?

#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. 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

Solution

  • MSVC Status of "Guarenteed copy elision" seems to buggy even with latest released version of MSVC (VS17 version 15.7.6).

    See for example this ticked: https://developercommunity.visualstudio.com/content/problem/217997/guaranteed-copy-elision-incomplete-in-1562.html

    UPDATE: MS has fixed the issue with latest VS17 version 15.8.1