[英]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.