我有一个返回常量char指针的方法。它使用std::string
并最终返回其c_str()
字符指针。
const char * returnCharPtr()
{
std::string someString;
// some processing!.
return someString.c_str();
}
我从COVERITY工具得到一份报告,上述说法不是很好。我已经谷歌搜索并发现返回的char指针,只要someString
遇到它的破坏就会失效。
鉴于此,如何解决这个问题?如何准确返回char指针?
返回std::string
可以解决此问题。但我想知道是否还有其他方法可以做到这一点。
答案 0 :(得分:20)
此代码中发生的事情是:
const char * returnCharPtr()
{
std::string someString("something");
return someString.c_str();
}
std::string
的实例 - 它是具有自动存储持续时间的对象someString
被破坏并且其内部存储器被清除最佳解决方案:返回一个对象:
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
成员。可以在一段时间后删除数据,以便不再永久保留数据。