I’ve been learning c++17 changes by applying them to some old code, and found that returning std::string_view
produces silent bugs, and it seems to me that a reference to temporary compiler warning would be appropriate. Is there a way I can generate one?
I am using g++ 9.3.0, with compiler flags -ggdb -Wall -std=c++17
. I also tried clang and clang-tidy/clazy without a warning.
First of all, I have recently learned that it’s probably best to only use std::string_view
to replace const std::string &
in parameters, and not as a return value. This article explained it pretty well to me. Unfortunately I’m not seeing it generally presented that way, so I wonder if others are having the same issue.
(section 1 in the code below)
I know that attempting to return a non-const reference to a temporary string will not compile. The same is true whether that reference is a std::string &
or a std::string_view &
.
The same compiler error occurs if I attempt to return a non-const std::string_view &
reference to the permanent string theString
.
(section 2 in the code below)
I also know that if I attempt to return a const reference to a temporary string, it will compile, but the compiler will provide a warning that I have returned a reference to a temporary. As in section 1, the same is true whether that reference is a const std::string &
or a const std::string_view &
.
Also as in section 1, the same reference to temporary compiler warning occurs if I attempt to return a const std::string_view &
reference to the permanent string theString
.
(section 3 in the code below)
If I try to return a std::string_view
from a permanent, or from a reference to a permanent, it works fine, of course, but if I try to return from a temporary, it compiles without warning, but its use produces garbage.
Shouldn’t the compiler produce the same reference to temporary warning as in section 2 of the code? Sure, it’s not a reference per se, but then theString
is not a temporary, and that warning was applied there. Is there a way I can generate such a warning? Perhaps a compiler option I’m missing for either g++ or clang-tidy?
#include <string>
#include <string_view>
#include <iostream>
class C1
{
public:
C1() { theString = "Initial string."; }
// produce a temporary std::string
std::string getS() { return theString; }
// Returning string_view works fine if called on a reference to a permenant string.
std::string &getRef() { return theString; }
// SECTION1: These won't compile: can't bind non-const lvalue reference to the rvalue
// std::string &getSref() { return getS(); }
// std::string_view &getSVref() { return getS(); }
// std::string_view &getSVref() { return theString; }
// SECTION2: These produce compiler warning: reference to temporary, and use gives seg fault
const std::string &getSref() { return getS(); }
const std::string_view &getSVrefFromTemp() { return getS(); }
// also produces compiler warning: reference to temporary,
// even though theString is not temporary
const std::string_view &getSVrefFromPerm() { return theString; }
// SECTION3:
std::string_view getSVfromPerm() { return theString; } // works fine
std::string_view getSVfromRef() { return getRef(); } // works fine
std::string_view getSVfromTemp() { return getS(); } // silent bug.
private:
std::string theString;
};
int main()
{
C1 myClass;
// SECTION2: produces seg fault
// std::cout << "getSref: \"" << myClass.getSref() << "\"." << std::endl;
// std::cout << "getSVrefFromTemp: \"" << myClass.getSVrefFromTemp() << "\"." << std::endl;
// std::cout << "getSVrefFromPerm: \"" << myClass.getSVrefFromPerm() << "\"." << std::endl;
// SECTION3: These compile silently.
// works fine
std::cout << "getSVfromPerm: \"" << myClass.getSVfromPerm() << "\"." << std::endl;
// works fine
std::cout << "getSVfromRef: \"" << myClass.getSVfromRef() << "\"." << std::endl;
// silent bug prints garbage
std::cout << "getSVfromTemp: \"" << myClass.getSVfromTemp() << "\"." << std::endl;
}
Is there a way to get a compiler warning when returning a by-value
string_view
from a temporary?
There is! Use clang 10. For this program:
#include <string>
#include <string_view>
struct C
{
std::string getS();
std::string_view getSVfromTemp() { return getS(); }
};
clang-10 emits:
<source>:7:47: warning: returning address of local temporary object [-Wreturn-stack-address]
std::string_view getSVfromTemp() { return getS(); }
^~~~~~