C++ 为什么对返回字符串的函数调用std::string.c_str()不起作用?

C++ 为什么对返回字符串的函数调用std::string.c_str()不起作用?,c++,string,temporary,object-lifetime,C++,String,Temporary,Object Lifetime,我有以下代码: std::string getString() { std::string str("hello"); return str; } int main() { const char* cStr = getString().c_str(); std::cout << cStr << std::endl; // this prints garbage } std::string getString(){ std::string

我有以下代码:

std::string getString() {
    std::string str("hello");
    return str;
}

int main() {
    const char* cStr = getString().c_str();
    std::cout << cStr << std::endl; // this prints garbage
}
std::string getString(){
std::string str(“hello”);
返回str;
}
int main(){
const char*cStr=getString().c_str();
标准::cout
getString()
将返回
str
的副本(
getString()
按值返回)

没错

因此,
str
的副本将在
main()
中保持“活动”,直到
main()
返回


否,返回的副本是一个临时的
std::string
,它将在创建它的语句结束时销毁,即在
std::cout之前。这里的问题是,您返回的是一个临时变量,并且超过了它
您正在执行的临时变量c_str函数

“c_str()函数返回一个指向数组的指针,该数组包含以null结尾的 表示当前数据的字符序列(即C字符串) 字符串对象的值( [)

在这种情况下,指针指向的是现在不存在的内存位置

std::string getString() {
        std::string str("hello");
        return str; // Will create Temporary object as it's return by value}

    int main() {
         const char* cStr = getString().c_str(); // Temporary object is destroyed
        std::cout << cStr << std::endl; // this prints garbage }
std::string getString(){
std::string str(“hello”);
return str;//将创建临时对象,因为它按值返回}
int main(){
const char*cStr=getString().c_str();//临时对象已销毁

std::cout正如其他人所提到的,您正在使用一个指向临时文件的指针,该指针已被删除-这是免费使用后堆的一个经典示例

我可以补充到其他人的答案中的一点是,你可以很容易地用消毒剂检测到这种用法,或者处理消毒剂

例如:

#include <string>
#include <iostream>

std::string get()
{
  return "hello";
}

int main()
{
  const char* c = get().c_str();
  std::cout << c << std::endl;
}
#包括
#包括
std::string get()
{
回复“你好”;
}
int main()
{
const char*c=get().c_str();

std::难道你的代码对我来说很好吗。@Priyansgool Undefined behavior有时就是这样。我不知道为什么会出现Undefined中的行为。如果你在循环中调用它,你会期望所有的行为都保持活动直到
main()
返回?可能与std::string重复,但将临时std::string保存在一个变量中,如:std::string str=getString();不会销毁副本?为什么不?是因为=使用了副本构造函数吗?很抱歉,我无法理解这一点。我同意str将被销毁,但我已经将string.c_str的值存储在另一个变量中。它应该打印hello。@FakeJake是的,命名变量
str
将从临时变量(即使副本通常由RVO省略),则
str
将在
main()
结束之前有效,因此在
main()
中使用
str.c_str()
是安全的
将返回一个指针,是的,我们可以将指针保存到另一个变量,但指针指向的内存(由
std::string
分配)将在
std::string
被销毁时被销毁。然后保存在另一个变量中的指针将是一个悬空指针。@priyansgoel我已经添加了一些解释在我的回答中是on。即使它看起来工作得很好,对释放内存的解引用是UB,任何事情都是可能的。我猜你的意思是“释放后使用堆”;这里不一定涉及任何堆(字符串可能使用SSO以避免需要分配缓冲区)
void f(string& s1, string& s2, string& s3)
{

    const char* cs = (s1 + s2).c_str();
    cout << cs ;
    if (strlen(cs=(s2+s3).c_str())<8 && cs[0]==´a´) {
        // cs used here
    }

}
std::string getString() {
        std::string str("hello");
        return str; // Will create Temporary object as it's return by value}

    int main() {
         const char* cStr = getString().c_str(); // Temporary object is destroyed
        std::cout << cStr << std::endl; // this prints garbage }
#include <string>
#include <iostream>

std::string get()
{
  return "hello";
}

int main()
{
  const char* c = get().c_str();
  std::cout << c << std::endl;
}
=================================================================
==2951==ERROR: AddressSanitizer: heap-use-after-free on address 0x60300000eff8 at pc 0x7f78e27869bb bp 0x7fffc483e670 sp 0x7fffc483de20
READ of size 6 at 0x60300000eff8 thread T0
    #0 0x7f78e27869ba in strlen (/usr/lib64/libasan.so.2+0x6d9ba)
    #1 0x39b4892ba0 in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (/usr/lib64/libstdc++.so.6+0x39b4892ba0)
    #2 0x400dd8 in main /tmp/tmep_string/main.cpp:12
    #3 0x39aa41ed5c in __libc_start_main (/lib64/libc.so.6+0x39aa41ed5c)
    #4 0x400c48  (/tmp/tmep_string/a.out+0x400c48)

0x60300000eff8 is located 24 bytes inside of 30-byte region [0x60300000efe0,0x60300000effe)
freed by thread T0 here:
    #0 0x7f78e27ae6ea in operator delete(void*) (/usr/lib64/libasan.so.2+0x956ea)
    #1 0x39b489d4c8 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (/usr/lib64/libstdc++.so.6+0x39b489d4c8)
    #2 0x39aa41ed5c in __libc_start_main (/lib64/libc.so.6+0x39aa41ed5c)

previously allocated by thread T0 here:
    #0 0x7f78e27ae1aa in operator new(unsigned long) (/usr/lib64/libasan.so.2+0x951aa)
    #1 0x39b489c3c8 in std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (/usr/lib64/libstdc++.so.6+0x39b489c3c8)
    #2 0x400c1f  (/tmp/tmep_string/a.out+0x400c1f)

SUMMARY: AddressSanitizer: heap-use-after-free ??:0 strlen
Shadow bytes around the buggy address:
  0x0c067fff9da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9dc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9dd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9de0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c067fff9df0: fa fa fa fa fa fa fa fa fa fa fa fa fd fd fd[fd]
  0x0c067fff9e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9e20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9e30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9e40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==2951==ABORTING