从内部使用静态std :: string的函数返回const char *是否安全?

时间:2017-08-09 10:14:01

标签: c++

我正在查看以下代码(简化)并问自己使用此returnMsg函数有多安全:

#include <iostream>

using namespace std;

const char *returnMsg(const char *msg)
{
    static std::string message;

    message = msg;

    return message.c_str();
}

int main(int argc, char *argv[])
{
    const char *msg1 = returnMsg("Hello world");
    printf("msg1 = %p\n", msg1);
    cout << msg1 << endl;

    const char *msg2 = returnMsg("Good bye");
    printf("msg2 = %p\n", msg2);
    cout << msg2 << endl;

    cout << msg1 << endl;

    return 0;
}

输出是:

msg1 = 0x23a6028
Hello world
msg2 = 0x23a6028
Good bye
Good bye

msg2写了两次,这是我所期望的,因为静态消息变量在程序的生命周期内保留在内存中,并且没有内存重新分配,因此在msg1地址处写的内容被替换通过msg2的新内容。

但是,如果msg2的大小较大,则std::string message变量内部会有内部重新分配,输出为:

msg1 = 0x1cc6028
Hello world
msg2 = 0x1cc6058
Good bye looooooooooooooooooooooooooooooooooooooooong
Hello world

但我想无法保证msg1地址将来不会重复使用,因此对msg1内容的新访问最终可能会显示不同且不连贯的内容。

这个函数是否需要以不同的方式编写才能在没有上述限制的情况下使用它?

2 个答案:

答案 0 :(得分:9)

  

从内部使用静态std :: string的函数返回const char *是否安全?

是的,这是安全的。

但是在指针失效后使用该指针是不安全的,这就是所示程序的作用。如果重新分配,则在对该函数的连续调用中赋值将使指针无效。因此,指针只有在下次调用该函数时才会安全(这将导致重新分配)。

  

这个函数是否需要以不同的方式编写才能在没有上述限制的情况下使用它?

该功能具有所描述的限制,因此当然必须以不同的方式编写,以免出现这些限制。

你的方法的核心问题是你只有一个静态字符串,但想要存储多个字符串而不丢弃任何早期字符串。所以,似乎你需要一大堆静态字符串:

const char *returnMsg(const char *msg)
{
    static std::forward_list<std::string> messages;
    messages.emplace_front(msg);
    return messages.front().c_str();
}

虽然这可以按照您的预期运作,但这很愚蠢。考虑一下你是否真的想要为执行的其余部分存储所有字符串。如果没有,则静态存储不是解决方案。

答案 1 :(得分:3)

上面的代码会导致未定义的行为。只需查看c_str()文档:

  

从c_str()获得的指针可以通过以下方式无效:

     
      
  • 将对字符串的非const引用传递给任何标准库函数,或
  •   
  • 在字符串上调用非const成员函数,不包括operator [],at(),front(),back(),begin(),rbegin(),end()和   雷德()。
  •   

当您在returnMsg()内第二次致电operator=时,msg1无效,使用未定义的行为