5

Consider this snippet:

#include <iostream>
#include <string>
#include <string_view>
using namespace std::literals;

class A
{
 public:
    std::string to_string() const noexcept
       {
        return "hey"; // "hey"s
       }

    std::string_view to_stringview() const noexcept
       {
        return "hello"; // "hello"sv
       }
};

int main()
{
    A a;
    std::cout << "The class says: " << a.to_string() << '\n';
    std::cout << "The class says: " << a.to_stringview() << '\n';
}

I was naively expecting some warning in to_stringview() like returning a reference of a local temporary, but both g++ and clang say nothing, so this code seems legit and works.

Since this generates the expected warning:

    const std::string& to_string() const noexcept
       {
        return "hey"s;
       }

I was wondering by which mechanism the lifetime of "hello" is different from the lifetime of "hey".

MatG
  • 574
  • 2
  • 7
  • 19
  • 1
    Well, if you tried returning a `const std::string_view&`, you'd get [the same warning](https://gcc.godbolt.org/z/8zvvP9r99). – Nathan Pierson Aug 23 '21 at 13:29
  • You seem to not be comparing like with like. Your last snippet returns (explicitly) a `const` reference but the equivalent in the earlier snippet (using "hey" not "hello") returns a `string` object *by value*, constructed from the literal. Using return-by-reference for the `string_view` function has the same issue, and is a bit trickier to explain ... is that what you actually meant? – Adrian Mole Aug 23 '21 at 13:38
  • @AdrianMole Hi Adrian, `string_view` is already somewhat a reference, so is comparable (kinda) with `std::string&` – MatG Aug 23 '21 at 13:51
  • Thing is, a `string` returned *by value* will make its own *copy* of the source data; however, a `string_view` will just copy the address of the source data. But, as explained in the answer, string literals are static anyway. – Adrian Mole Aug 23 '21 at 13:56
  • Note, the function that returns a string should not be marked `noexcept` because it can throw. – Oleksandr Kozlov May 14 '22 at 17:07
  • @OleksandrKozlov Is the reason that the equivalent of `std::string(char*)` may have to allocate memory on the heap (if there's no small string optimization)? – MatG May 14 '22 at 18:38
  • Yes, because it may allocate memory. If a function returns a small string, the allocation most likely won't happen due to SSO. However, SSO is an implementation detail. A corresponding string constructor is not marked `noexcept`. Almost always, we don't want to call a function/constructor that might throw an exception from a `noexcept` function. – Oleksandr Kozlov May 15 '22 at 13:42

1 Answers1

7

but both g++ and clang say nothing, so this code seems legit and works.

You cannot deduce latter from the former. A lot of non-legit code produces no warnings.

That said, string literals have static storage duration, so there is no problem with their lifetime. to_stringview is legit indeed.

P.S. String literals are arrays of char.

I was wondering by which mechanism the lifetime of "hello" is different from the lifetime of "hey".

There is no difference between the lifetime of those two string literals. But "hey"s is not a string literal. It is a "user defined" literal that creates a temporary instance of the class std::string. That temporary object has no static storage duration.

eerorika
  • 232,697
  • 12
  • 197
  • 326