如何返回std :: string.c_str()

时间:2014-03-11 15:38:00

标签: c++ string pointers c++11 return

我有一个返回常量char指针的方法。它使用std::string并最终返回其c_str()字符指针。

const char * returnCharPtr()
{
    std::string someString;

    // some processing!.

    return someString.c_str();
}

我从COVERITY工具得到一份报告,上述说法不是很好。我已经谷歌搜索并发现返回的char指针,只要someString遇到它的破坏就会失效。

鉴于此,如何解决这个问题?如何准确返回char指针?

返回std::string可以解决此问题。但我想知道是否还有其他方法可以做到这一点。

10 个答案:

答案 0 :(得分:20)

此代码中发生的事情是:

const char * returnCharPtr()
{
    std::string someString("something");
    return someString.c_str();
}
  1. 创建了std::string的实例 - 它是具有自动存储持续时间的对象
  2. 返回指向此字符串内部存储器的指针
  3. 对象someString被破坏并且其内部存储器被清除
  4. 此函数的调用方接收 悬空指针 (无效指针),产生 未定义的行为
  5. 最佳解决方案:返回一个对象

    std::string returnString()
    {
        std::string someString("something");
        return someString;
    }
    

答案 1 :(得分:11)

在C ++中,最简单的方法就是返回std::string(由于像RVO和C ++ 11移动语义这样的优化,这也很有效):

std::string returnSomeString()
{
    std::string someString;

    // some processing...

    return someString;
}

如果您确实需要原始C char*指针,则可以随时在返回的值上调用.c_str(),例如

// void SomeLegacyFunction(const char * psz)

// .c_str() called on the returned string, to get the 'const char*' 
SomeLegacyFunction( returnSomeString().c_str() );

如果你真的想从函数返回一个char*指针,你可以动态在堆上分配字符串内存(例如使用new[]),并返回一个指针对此:

// NOTE: The caller owns the returned pointer, 
// and must free the string using delete[] !!!
const char* returnSomeString()
{
    std::string someString;

    // some processing...

    // Dynamically allocate memory for the returned string
    char* ptr = new char[someString.size() + 1]; // +1 for terminating NUL

    // Copy source string in dynamically allocated string buffer
    strcpy(ptr, someString.c_str());

    // Return the pointer to the dynamically allocated buffer
    return ptr;
}

另一种方法是提供目标缓冲区指针缓冲区大小(以避免缓冲区溢出!)作为函数参数:

void returnSomeString(char* destination, size_t destinationSize)
{
    std::string someString;

    // some processing...

    // Copy string to destination buffer.
    // Use some safe string copy function to avoid buffer overruns.
    strcpy_s(destination, destinationSize, someString.c_str());
}

答案 2 :(得分:6)

由于此问题标记为C,请执行以下操作:

#define _POSIX_C_SOURCE 200809L
#include <string.h>

const char * returnCharPtr()
{
  std::string someString;

  // some processing!.

  return strdup(someString.c_str()); /* Dynamically create a copy on the heap. */
}

如果不再使用,请不要忘记free()函数返回的内容。

答案 3 :(得分:3)

嗯,COVERITY是正确的。您当前方法失败的原因是因为您在函数内创建的std::string实例只有在该函数运行时才有效。一旦程序离开函数的作用域,将调用std :: string的析构函数,这将是字符串的结尾。

但如果你想要的是一个C字符串,那么......

const char * returnCharPtr()
{
    std::string someString;

    // some processing!.

    char * new_string = new char[someString.length() + 1];

    std::strcpy(new:string, someString.c_str());

    return new_string;
}

但等等......这几乎就像回归std::string一样,不是吗?

std::string returnCharPtr()
{
    std::string someString;

    // some processing!.

    return new_string;
}

这会将您的字符串复制到函数范围之外的新字符串。它可以工作,但它确实创建了一个新的字符串副本。

感谢返回值优化,这不会创建副本(感谢所有更正!)。

因此,另一个选项是将参数作为参数传递,因此您在函数中处理字符串但不创建新副本。 :

void returnCharPtr(std::string & someString)
{
    // some processing!.
}

或者,如果你想要C-Strings,你需要注意字符串的长度:

void returnCharPtr(char*& someString, int n) // a reference to pointer, params by ref
{
    // some processing!.
}

答案 4 :(得分:1)

最好的方法是返回std::string,为您自动执行内存管理。另一方面,如果您真的要返回一个const char*指向您在returnCharPtr内分配的内存,那么它必须被其他人明确释放。< / p>

坚持std::string

答案 5 :(得分:1)

你可以传入指向你的字符串的指针,让方法直接操纵它(即避免完全返回)

void returnCharPtr(char* someString)
{    
    // some processing!
    if(someString[0] == 'A')
       someString++;
}

答案 6 :(得分:1)

您的选择是:

返回std::string

将缓冲区传递给将保存新字符缓冲区的returnCharPtr()。这要求您验证提供的缓冲区是否足以容纳字符串。

char内创建一个新的returnCharPtr()数组,将缓冲区复制到新数组中并返回指向该数组的指针。这要求调用者显式调用delete []关于他们未使用new显式创建的内容,或立即将其放入智能指针类中。 如果你返回一个智能指针,这个解决方案会有所改进,但直接返回std::string真的更合理。

选择第一个;返回std::string。 它是迄今为止最简单,最安全的选择。

答案 7 :(得分:1)

问题是在函数末尾销毁someString,函数返回指向不存在数据的指针。

在使用返回的char指针之前,不要返回可能被销毁的字符串.c_str()

而不是......

const char* function()
{
    std::string someString;
    // some processing!
    return someString.c_str();
}

//...

useCharPtr(function());

使用

std::string function()
{
    std::string someString;
    // some processing!
    return someString;
}

//...

useCharPtr(function().c_str());

答案 8 :(得分:1)

如果您可以自由更改returnCharPtr的返回值,请将其更改为std::string。这将是返回字符串最干净的方法。如果不能,则需要为返回的字符串分配内存,从std::string复制到该字符串并返回指向已分配内存的指针。您还必须确保删除调用函数中的内存。由于调用者将负责释放内存,我会将返回值更改为char*

char* returnCharPtr() 
{
    std::string someString;

    // some processing!.

    char* cp = new char[someString.length()+1];
    strcpy(cp, someString.c_str());
    return cp;
}

答案 9 :(得分:1)

在其他答案中没有引起的解决方案。

如果您的方法是类的成员,请执行以下操作:

class A {
public:
    const char *method();
};

如果类实例超出了指针的用途,你可以这样做:

class A {
public: 
    const char *method() {
        string ret = "abc";
        cache.push_back(std::move(ret));
        return cache.last().c_str();
    }
private:
    vector<string> cache; //std::deque would be more appropriate but is less known
}

这样指针在A的销毁之前一直有效。

如果函数不是类的一部分,它仍然可以使用类来存储数据(如函数的static变量或可以全局引用的外部类实例,或者甚至是班级的static成员。可以在一段时间后删除数据,以便不再永久保留数据。