Caching a const char * as a return type

2020-07-14 09:43发布

Was reading up a bit on my C++, and found this article about RTTI (Runtime Type Identification): http://msdn.microsoft.com/en-us/library/70ky2y6k(VS.80).aspx . Well, that's another subject :) - However, I stumbled upon a weird saying in the type_info-class, namely about the ::name-method. It says: "The type_info::name member function returns a const char* to a null-terminated string representing the human-readable name of the type. The memory pointed to is cached and should never be directly deallocated."

How can you implement something like this yourself!? I've been struggling quite a bit with this exact problem often before, as I don't want to make a new char-array for the caller to delete, so I've stuck to std::string thus far.

So, for the sake of simplicity, let's say I want to make a method that returns "Hello World!", let's call it

const char *getHelloString() const;

Personally, I would make it somehow like this (Pseudo):

const char *getHelloString() const
{
  char *returnVal = new char[13];
  strcpy("HelloWorld!", returnVal);

  return returnVal
}

.. But this would mean that the caller should do a delete[] on my return pointer :(

Thx in advance

12条回答
放荡不羁爱自由
2楼-- · 2020-07-14 09:56

Be careful when implementing a function that allocates a chunk of memory and then expects the caller to deallocate it, as you do in the OP:

const char *getHelloString() const
{
  char *returnVal = new char[13];
  strcpy("HelloWorld!", returnVal);

  return returnVal
}

By doing this you are transferring ownership of the memory to the caller. If you call this code from some other function:

int main()
{
  char * str = getHelloString();
  delete str;
  return 0;
}

...the semantics of transferring ownership of the memory is not clear, creating a situation where bugs and memory leaks are more likely.

Also, at least under Windows, if the two functions are in 2 different modules you could potentially corrupt the heap. In particular, if main() is in hello.exe, compiled in VC9, and getHelloString() is in utility.dll, compiled in VC6, you'll corrupt the heap when you delete the memory. This is because VC6 and VC9 both use their own heap, and they aren't the same heap, so you are allocating from one heap and deallocating from another.

查看更多
倾城 Initia
3楼-- · 2020-07-14 09:56

The advice given that warns about the lifetime of the returned string is sound advise. You should always be careful about recognising your responsibilities when it comes to managing the lifetime of returned pointers. The practise is quite safe, however, provided the variable pointed to will outlast the call to the function that returned it. Consider, for instance, the pointer to const char returned by c_str() as a method of class std::string. This is returning a pointer to the memory managed by the string object which is guaranteed to be valid as long as the string object is not deleted or made to reallocate its internal memory.

In the case of the std::type_info class, it is a part of the C++ standard as its namespace implies. The memory returned from name() is actually pointed to static memory created by the compiler and linker when the class was compiled and is a part of the run time type identification (RTTI) system. Because it refers to a symbol in code space, you should not attempt to delete it.

查看更多
趁早两清
4楼-- · 2020-07-14 09:59

Something like this would do:

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

EDIT: Something that occurred to me is that a good replacement for this could be returning a boost::shared_pointer instead. That way the caller can hold onto it as long as they want and they don't have to worry about explicitly deleting it. A fair compromise IMO.

查看更多
爷的心禁止访问
5楼-- · 2020-07-14 10:01

What I've often done when I need this sort of functionality is to have a char * pointer in the class - initialized to null - and allocate when required.

viz:

class CacheNameString
{
    private: 
        char *name;
    public:
        CacheNameString():name(NULL)  { }

    const char *make_name(const char *v)
    {
        if (name != NULL)
            free(name);

        name = strdup(v);

        return name;
    }

};
查看更多
Explosion°爆炸
6楼-- · 2020-07-14 10:03

It's probably done using a static buffer:

const char* GetHelloString()
{
    static char buffer[256] = { 0 };
    strcpy( buffer, "Hello World!" );
    return buffer;
}

This buffer is like a global variable that is accessible only from this function.

查看更多
你好瞎i
7楼-- · 2020-07-14 10:05

How about this:

const char *getHelloString() const
{
    return "HelloWorld!";
}

Returning a literal directly means the space for the string is allocated in static storage by the compiler and will be available throughout the duration of the program.

查看更多
登录 后发表回答