简体   繁体   中英

What happens when a string literal is passed to a function accepting a const std::string & in C++?

as you can probably guess from the title, I want to understand what exactly happens when a std::string is passed to a function as a const reference, because earlier today I ran into a few situations I didn't quite understand entirely. Here's some code:

#include <string>
#include <stdio.h>

struct Interface {
    virtual void String1(const std::string &s) = 0;
    virtual void String2(const std::string &s) = 0;
    virtual void DoSomething() = 0;
};

struct SomeClass : public Interface {
    void String1(const std::string &s) override { s1 = s.c_str(); }
    void String2(const std::string &s) override { s2 = s.c_str(); }
    void DoSomething() override { printf("%s - %s\n", s1, s2); }

private:
    const char *s1, *s2;
};

struct AnotherClass {
    AnotherClass(Interface *interface) : interface(interface) {
        this->interface->String1("Mean string literal");
    }

    void DoTheThing() {
        std::string s("Friendlich string literal");
        interface->String2(s);
        interface->DoSomething();
    }

private:
    Interface *interface = nullptr;
};

int main(int argc, char **argv) {
    SomeClass some_class;
    AnotherClass another_class(&some_class);

    another_class.DoTheThing();
}

When using const char * for s1 and s2 in SomeClass the program prints Friendlich string literal - Friendlich string literal or [some rubbish] - Friendlich string literal instead of Mean string literal - Friendlich string literal as I was expecting.

When switching to std::string for s1 and s2 it works as expected, printing Mean string literal - Friendlich string literal .

What a coworker and I are guessing is that the string in the ctor of AnotherClass goes out of scope but SomeClass still has the address of the string stored because of c_str().

When using std::string instead of const char * for s1 and s2 it actually makes a copy, so going out of scope isn't a problem. Like this:

struct SomeClass : public Interface {
    void String1(const std::string &s) override { s1 = s; }
    void String2(const std::string &s) override { s2 = s; }
    void DoSomething() override { printf("%s - %s\n", s1.c_str(), s2.c_str()); }

private:
    std::string s1, s2;
};

So... what's really happening? Why doesn't it work with const char *? Why does it work with std::string?

When you pass a string literal to a function that accepts const std::string& , the following events occur:

  • The string literal is converted to const char*
  • A temporary std::string object is created. Its internal buffer is allocated, and initialized by copying the data from the const char* until the terminating null is seen. The parameter refers to this temporary object.
  • The function body runs.
  • Assuming the function returns normally, the temporary object is destroyed at some unspecified point between when the function returns and the end of the calling expression.

If the c_str() pointer is saved from the parameter, it becomes a dangling pointer after the temporary object is destroyed since it points into the temporary object's internal buffer.

A similar problem will occur if the function accepts std::string . The std::string object will be created when the function is called and destroyed when the function returns or soon afterward, so any saved c_str() pointer will become dangling.

If the function accepts const std::string& and the argument has type std::string , however, no new object is created when the function is called. The reference refers to the existing object. The c_str() pointer will remain valid until the original std::string object is destroyed.

A char * isn't an object, it's a pointer to characters that exist in some other context. If you assign such a pointer to a temporary variable, or data contained within a temporary variable, it will be invalid when the temporary is destroyed. Using it after that point produces undefined behavior.

When you have member variables of std::string , a copy is made at the time of assignment so it doesn't matter if the temporary is destroyed or not.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM