将常量字符*缓存为返回类型 在我的C++上读了一点,找到了关于RTI(运行时类型识别)的文章: . 嗯,这是另一个主题:)-然而,我在type_info-类中偶然发现了一个奇怪的说法,即关于::name-方法。它说:“type\u info::namemember函数将const char*返回到一个以null结尾的字符串,该字符串表示该类型的可读名称。指向的内存被缓存,不应直接释放。”
你自己怎么能实现这样的事情!?我以前经常遇到这个问题,因为我不想为调用者创建一个新的将常量字符*缓存为返回类型 在我的C++上读了一点,找到了关于RTI(运行时类型识别)的文章: . 嗯,这是另一个主题:)-然而,我在type_info-类中偶然发现了一个奇怪的说法,即关于::name-方法。它说:“type\u info::namemember函数将const char*返回到一个以null结尾的字符串,该字符串表示该类型的可读名称。指向的内存被缓存,不应直接释放。”,c++,char,return-value,C++,Char,Return Value,你自己怎么能实现这样的事情!?我以前经常遇到这个问题,因为我不想为调用者创建一个新的char-数组来删除,所以到目前为止我一直坚持使用std::string 因此,为了简单起见,假设我想创建一个返回“Hello World!”的方法,让我们调用它 const char *getHelloString() const; 就我个人而言,我会这样做(伪): 。。但这意味着调用方应该对我的返回指针执行delete[]:( 提前Thx这个怎么样: const char *getHelloString()
char
-数组来删除,所以到目前为止我一直坚持使用std::string
因此,为了简单起见,假设我想创建一个返回“Hello World!”
的方法,让我们调用它
const char *getHelloString() const;
就我个人而言,我会这样做(伪):
。。但这意味着调用方应该对我的返回指针执行delete[]
:(
提前Thx这个怎么样:
const char *getHelloString() const
{
return "HelloWorld!";
}
直接返回文本意味着编译器在静态存储中为字符串分配空间,并且在整个程序期间都可用。我认为,因为他们知道这些字符串的数量有限,所以他们只会永远保留它们。在某些情况下,您可以这样做,但是一般来说,std::string会更好
他们还可以查找新的调用,查看是否已生成该字符串并返回相同的指针。同样,根据您正在执行的操作,这可能对您也很有用。这可能是使用静态缓冲区完成的:
const char* GetHelloString()
{
static char buffer[256] = { 0 };
strcpy( buffer, "Hello World!" );
return buffer;
}
这个缓冲区就像一个只能通过这个函数访问的全局变量。好吧,如果我们只讨论一个函数,你总是希望返回相同的值。这很简单
const char * foo()
{
static char[] return_val= "HelloWorld!";
return return_val;
}
棘手的一点是,当你开始做缓存的结果,然后你必须考虑线程,或者当你的缓存失效,并试图在线程本地存储中存储东西。但是如果它只是一个一次性输出,立即复制,这就行了。 或者,如果没有固定大小,则必须使用任意大小的静态缓冲区,最终可能会有太大的缓冲区,或者使用托管类,例如
std::string
const char * foo()
{
static std::string output;
DoCalculation(output);
return output.c_str();
}
还有函数签名
const char *getHelloString() const;
仅适用于成员函数。
在这个时候,你不需要处理静态函数局部变量,只需要使用一个成员变量。 你不能依赖GC;这是C++。这意味着你必须保持内存可用,直到程序终止。你根本不知道什么时候安全删除[]。因此,如果你想构造并返回一个常量char*,简单的new[]它并返回它。接受不可避免的泄漏。为什么返回类型必须是
const
?不要将该方法视为get方法,而应将其视为create方法。我见过很多API要求您删除创建操作符/方法返回的内容。请确保您在文档中注意到这一点
/* create a hello string
* must be deleted after use
*/
char *createHelloString() const
{
char *returnVal = new char[13];
strcpy("HelloWorld!", returnVal);
return returnVal
}
当我需要这种功能时,我经常做的是在类中有一个char*指针——初始化为null——并在需要时分配 即:
这样做可以:
const char *myfunction() {
static char *str = NULL; /* this only happens once */
delete [] str; /* delete previous cached version */
str = new char[strlen("whatever") + 1]; /* allocate space for the string and it's NUL terminator */
strcpy(str, "whatever");
return str;
}
编辑:我想到了一个很好的替代方法,那就是返回boost::shared_指针。这样,调用者可以保留它,只要他们愿意,而且他们不必担心显式删除它。这是一个公平的折衷办法。在实现分配一块内存和内存的函数时要小心然后期望调用者释放它,就像您在OP中所做的那样:
const char *getHelloString() const
{
char *returnVal = new char[13];
strcpy("HelloWorld!", returnVal);
return returnVal
}
这样做就是将内存的所有权转移给调用者。如果从其他函数调用此代码:
int main()
{
char * str = getHelloString();
delete str;
return 0;
}
…转移内存所有权的语义不清楚,这就造成了更容易出现错误和内存泄漏的情况
另外,至少在Windows下,如果这两个函数位于两个不同的模块中,则可能会损坏堆。特别是,如果main()位于hello.exe中,在VC9中编译,以及getHelloString()中是在utility.dll中,在VC6中编译,当您删除内存时,您将损坏堆。这是因为VC6和VC9都使用自己的堆,并且它们不是同一堆,因此您从一个堆分配,从另一个堆取消分配。警告返回字符串的生存期的建议是合理的建议。您应该在管理返回指针的生命周期时,要小心识别你的职责。但是,实践是相当安全的,但是如果指向的变量将超过调用返回函数的函数。例如,考虑由<代码> CyScript()返回的const char指针。作为类的一种方法
std::string
。这将返回一个指向由string对象管理的内存的指针,只要string对象没有被删除或重新分配其内部内存,该指针就保证有效
<> > <代码> STD::Type OnngIs<代码>类,它是C++标准的一部分,其命名空间意味着。从
const char *getHelloString() const
{
char *returnVal = new char[13];
strcpy("HelloWorld!", returnVal);
return returnVal
}
int main()
{
char * str = getHelloString();
delete str;
return 0;
}
#include <cstdio>
#include <typeinfo>
#include <vector>
int main(int argc, char* argv[]) {
std::vector<int> v;
const type_info& ti = typeid(v);
const char* n = ti.name();
printf("%s\n", n);
return 0;
}
0:000> ?? n
char * 0x00000000`00857290
"class std::vector<int,class std::allocator<int> >"
0:000> ln 0x00000000`00857290
0:000>
0:000> !heap -x 0x00000000`00857290
Entry User Heap Segment Size PrevSize Unused Flags
-------------------------------------------------------------------------------------------------------------
0000000000857280 0000000000857290 0000000000850000 0000000000850000 70 40 3e busy extra fill
struct __type_info_node {
void *memPtr;
__type_info_node* next;
};
extern __type_info_node __type_info_root_node;
...
_CRTIMP_PURE const char* __CLR_OR_THIS_CALL name(__type_info_node* __ptype_info_node = &__type_info_root_node) const;
class ICanReturnConstChars
{
std::stack<char*> cached_strings
public:
const char* yeahGiveItToMe(){
char* newmem = new char[something];
//write something to newmem
cached_strings.push_back(newmem);
return newmem;
}
~ICanReturnConstChars(){
while(!cached_strings.empty()){
delete [] cached_strings.back()
cached_strings.pop_back()
}
}
};