你能从函数返回 std::string 并存储 c_str() 的结果吗?

问题描述 投票:0回答:9

我们最近在大学进行了一次讲座,我们的教授告诉我们在使用不同语言编程时要注意的不同事项。 以下是 C++ 中的示例:

std::string myFunction()
{
    return "it's me!!";
}

int main()
{
    const char* tempString = myFunction().c_str();

    char myNewString[100] = "Who is it?? - ";
    strcat(myNewString, tempString);
    printf("The string: %s", myNewString);
}

失败的原因是

return "it's me!!"
使用
std::string
隐式调用
const char[]
构造函数。该字符串从函数返回,函数
c_str()
返回指向
std::string
中数据的指针。

理论是,由于从函数返回的字符串没有在任何地方被引用,因此应该立即释放它。 但是,运行此代码没有问题。这是为什么?

c++ undefined-behavior stdstring temporary-objects
9个回答
48
投票

你的分析是正确的。你所拥有的是未定义的行为。这意味着几乎任何事情都有可能发生。在您的情况下,用于字符串的内存虽然被解除分配,但在您访问它时仍然保留原始内容。这种情况经常发生,因为操作系统没有清除已解除分配的内存。它只是将其标记为可供将来使用。这不是 C++ 语言必须处理的事情:它实际上是操作系统实现细节。就 C++ 而言,包罗万象的“未定义行为”适用。


5
投票

我想释放并不意味着内存清理或清零。显然,这可能会在其他情况下导致段错误。


3
投票

我认为原因是堆栈内存没有被重写,所以可以得到原始数据。我创建了一个测试函数并在 strcat 之前调用它。

std::string myFunction()
{
    return "it's me!!";
}


void test()
{
    std::string str = "this is my class";
    std::string hi = "hahahahahaha";

    return;
}

int main(int argc, const char * argv[])
{
    const char* tempString = myFunction().c_str();


    test();
    char myNewString[100] = "Who is it?? - ";
    strcat(myNewString, tempString);
    printf("The string: %s\n", myNewString);

    return 0;
}

并得到结果:

The string: Who is it?? - hahahahahaha

这证明了我的想法。


3
投票

正如其他人提到的,根据 C++ 标准,这是未定义的行为。

之所以“有效”,是因为内存已返回给堆管理器,堆管理器保留该内存以供以后重用。内存尚未归还给操作系统,因此仍然属于该进程。这就是为什么访问释放的内存不会导致分段错误。然而,问题仍然存在,现在程序的两个部分(您的代码和堆管理器或新所有者)正在访问他们认为唯一属于他们的内存。这迟早会毁掉一切。


1
投票


1
投票


1
投票

还有其他方法来检测“问题”:

静态分析。
  • Valgrind 会捕获错误,向您显示有问题的操作(尝试通过 strcat 从已释放区域复制)和导致释放的释放。
Invalid read of size 1



   at 0x40265BD: strcat (mc_replace_strmem.c:262)
   by 0x80A5BDB: main() (valgrind_sample_for_so.cpp:20)
   [...]
Address 0x5be236d is 13 bytes inside a block of size 55 free'd
   at 0x4024B46: operator delete(void*) (vg_replace_malloc.c:480)
   by 0x563E6BC: std::string::_Rep::_M_destroy(std::allocator<char> const&) (in /usr/lib/libstdc++.so.6.0.13)
   by 0x80A5C18: main() (basic_string.h:236)
   [...]

   at 0x40265BD: strcat (mc_replace_strmem.c:262)
   by 0x80A5BDB: main() (valgrind_sample_for_so.cpp:20)
   [...]
Address 0x5be236d is 13 bytes inside a block of size 55 free'd
   at 0x4024B46: operator delete(void*) (vg_replace_malloc.c:480)
   by 0x563E6BC: std::string::_Rep::_M_destroy(std::allocator<char> const&) (in /usr/lib/libstdc++.so.6.0.13)
   by 0x80A5C18: main() (basic_string.h:236)
   [...]


唯一真正的方法是证明程序是正确的。但这对于过程语言来说确实很难,而 C++ 就更难了。

-1
投票


-1
投票

© www.soinside.com 2019 - 2024. All rights reserved.