簡體   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