2017-08-09 63 views
7

我在看下面的代码(简化),并问自己如何安全是它使用此returnMsg功能:从内部使用静态std :: string的函数返回const char *是否安全?

#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内容的新访问可能最终会显示不同的内容并且不一致。

此功能是否需要以不同的方式书写才能在没有上述限制的情况下使用它?

+0

实际上应该做的功能是什么?你可以用const char * msg2 =“Good bye”来代替'const char * msg2 = returnMsg(“Good bye”);''你不需要处理你现在遇到的问题 – user463035818

+0

@ tobi303我不能说OP,但考虑一个稍微不那么简单的例子,其中用非静态字符串调用函数,并且在该缓冲区不再存在之后使用指针。这个函数可以方便地通过复制它的内容到一个静态字符串来延长这个缓冲区的生命周期...但是直到下一次调用这个函数。 – user2079303

+0

@ user2079303没有冒犯性,但那是猜测和我会考虑这样的功能作为一个装饰的全球只是它比全球更坏 – user463035818

回答

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(); 
} 

尽管这可以像你期望的那样工作,但它很愚蠢。考虑你是否真的想为剩余的执行存储所有的字符串。如果不是,静态存储不是解决方案。

+0

NB。指针可能会失效,即在分配期间需要重新分配时。如果没有,这是安全的(虽然不是很明智)。 –

+0

@ engf-010我添加了限定条件,将其考虑在内。 – user2079303

3

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

从c_str()中得到的指针可以通过被无效:

  • 传递一个非const参照字符串到任何标准库函数或
  • (),front(),back(),begin(),rbegin(),end()和rend()在字符串上调用非const成员函数,但不包括运算符[]。

当你调用operator=的内部returnMsg()第二次,msg1无效,并用它是未定义行为

+0

注意。指针可能会失效,即在分配期间需要重新分配时。如果没有,这是安全的(虽然不是很明智)。 –

相关问题