[英]What happens when a string literal passed as const string& to a function?
[英]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.