繁体   English   中英

在 C++ 中将字符串文字传递给接受 const std::string & 的函数时会发生什么?

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

正如您可能从标题中猜到的那样,我想了解将 std::string 作为常量引用传递给函数时究竟会发生什么,因为今天早些时候我遇到了一些我不太完全理解的情况。 这是一些代码:

#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();
}

当在 SomeClass 中对 s1 和 s2 使用 const char * 时,程序会打印Friendlich string literal - Friendlich string literal[some rubbish] - Friendlich string literal而不是Mean string literal - Friendlich string literal,正如我所期待的。

当为 s1 和 s2 切换到 std::string 时,它按预期工作,打印Mean string literal - Friendlich string literal

我和一位同事猜测,AnotherClass 的 ctor 中的字符串超出了范围,但由于 c_str(),SomeClass 仍然存储了字符串的地址。

当对 s1 和 s2 使用 std::string 而不是 const char * 时,它实际上会创建一个副本,因此超出范围不是问题。 像这样:

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;
};

那么……到底发生了什么? 为什么它不适用于 const char *? 为什么它适用于 std::string?

当您将字符串文字传递给接受const std::string&的函数时,会发生以下事件:

  • 字符串文字被转换为const char*
  • 创建了一个临时的std::string对象。 它的内部缓冲区被分配,并通过从const char*复制数据来初始化,直到看到终止的 null。 参数指的是这个临时对象。
  • 函数体运行。
  • 假设函数正常返回,临时对象在函数返回和调用表达式结束之间的某个未指定点被销毁。

如果c_str()指针是从参数中保存的,那么在临时对象被销毁后它就变成了一个悬空指针,因为它指向临时对象的内部缓冲区。

如果函数接受std::string也会出现类似的问题。 std::string对象将在函数被调用时创建并在函数返回时或不久之后销毁,因此任何保存的c_str()指针都将变为悬空。

但是,如果函数接受const std::string&并且参数的类型为std::string ,则在调用函数时不会创建新对象。 引用是指现有对象。 c_str()指针将保持有效,直到原始std::string对象被销毁。

char *不是对象,它是指向存在于其他上下文中的字符的指针。 如果将这样的指针分配给临时变量或临时变量中包含的数据,则在销毁临时变量时它将无效。 在那之后使用它会产生未定义的行为。

当您拥有std::string成员变量时,会在赋值时进行复制,因此临时对象是否被销毁并不重要。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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