Is it possible * safely * to return TCHAR * from a function?

I created a function that converts all event notification codes into strings. Pretty simple stuff.

I have a bunch of constants like

const _bstr_t DIRECTSHOW_MSG_EC_ACTIVATE("A video window is being activated or deactivated."); const _bstr_t DIRECTSHOW_MSG_EC_BUFFERING_DATA("The graph is buffering data, or has stopped buffering data."); const _bstr_t DIRECTSHOW_MSG_EC_BUILT("Send by the Video Control when a graph has been built. Not forwarded to applications."); .... etc.... 

and my function

 TCHAR* GetDirectShowMessageDisplayText( int messageNumber ) { switch( messageNumber ) { case EC_ACTIVATE: return DIRECTSHOW_MSG_EC_ACTIVATE; case EC_BUFFERING_DATA: return DIRECTSHOW_MSG_EC_BUFFERING_DATA; case EC_BUILT: return DIRECTSHOW_MSG_EC_BUILT; ... etc ... 

No big deal. They took me 5 minutes to throw together.

... but I just don’t believe that I have all the possible values, so I want the default to return something like "Unexpected notification code (7410)" if no matches are found.

Unfortunately, I cannot think of returning a valid pointer without forcing the caller to delete the memory line ... which is not only unpleasant, but also contrary to the simplicity of the other returned values.

Therefore, I can not think of any way to do this without changing the return value to the parameter that the user passes to the buffer and the length of the string. What would my function look like

 BOOL GetDirectShowMessageDisplayText( int messageNumber, TCHAR* outBuffer, int bufferLength ) { ... etc ... 

I really don't want to do this. There must be a better way.

Whether there is a?

I am returning to C ++ after a 10-year hiatus, so if this is something obvious, don't reduce that I missed it for some reason.

+4
source share
9 answers

C ++? std :: string . This will not ruin the performance on any modern computer.

However, if you need to override this, you have three options:

  • Go with the buffer that has your example.
  • Ask users to delete the line after this. Many APIs like these provide their own delete function to delete each type of dynamically allocated return data.
  • Returns a pointer to a static buffer that you fill with a return string for each call. This has some drawbacks, however, in that it is not thread safe, and this can be confusing because the return value of the pointer will change the next time the function is called. If security other than streaming is acceptable and you document the limitations, then everything should be fine.
+2
source

Just declare the use of a static string as the default result:

 TCHAR* GetDirectShowMessageDisplayText( int messageNumber ) { switch( messageNumber ) { // ... default: static TCHAR[] default_value = "This is a default result..."; return default_value; } } 

You can also declare "default_value" outside the function.

UPDATE:

If you want to insert a message number in this line, it will not be thread safe (if you use multiple threads). However, the solution to this problem is to use a streaming string . Here is an example using Boost.Thread :

 #include <cstdio> #include <boost/thread/tss.hpp> #define TCHAR char // This is just because I don't have TCHAR... static void errorMessageCleanup (TCHAR *msg) { delete []msg; } static boost::thread_specific_ptr<TCHAR> errorMsg (errorMessageCleanup); static TCHAR * formatErrorMessage (int number) { static const size_t MSG_MAX_SIZE = 256; if (errorMsg.get () == NULL) errorMsg.reset (new TCHAR [MSG_MAX_SIZE]); snprintf (errorMsg.get (), MSG_MAX_SIZE, "Unexpected notification code (%d)", number); return errorMsg.get (); } int main () { printf ("Message: %s\n", formatErrorMessage (1)); } 

The only limitation of this solution is that the returned string cannot be passed by the client to another thread.

0
source

If you return the point to a string constant, the caller will not need to delete the line - they will only need it if you are new - each time using the memory used by the line. If you just return a pointer to a string element in the error message table, I would change the return type to TCHAR const * const , and you should be fine.

Of course, this will not prevent users of your code from trying to delete the memory that the pointer refers to, but there is only so much that you can do to prevent abuse.

0
source

Perhaps you have a static string buffer to which you return a pointer to:

 std::ostringstream ss; ss << "Unexpected notification code (" << messageNumber << ")"; static string temp = ss.str(); // static string always has a buffer return temp.c_str(); // return pointer to buffer 

This is not thread safe, and if you constantly hold the returned pointer and call it twice with another messageNumbers , they all point to the same buffer in temp - so both pointers now point to the same message. Decision? Return a std::string from the function - modern C ++ - style, try to avoid style pointers and buffers. (It looks like you could come up with a tstring that would be std::string in ANSI and std::wstring in unicode, although I would recommend just switching to unicode only ... do you really have any reason to support the non-code build?)

0
source

You are already using _bstr_t , so if you can just return them directly:

 _bstr_t GetDirectShowMessageDisplayText(int messageNumber); 

If you need to create another message at run time, you can also package it in _bstr_t . Ownership is now clear, and use is still simple thanks to RAII.
The overhead is negligible ( _bstr_t uses ref-counting), and the calling code can still use the conversion of _bstr_t to wchar_t* and char* if necessary.

0
source

You are returning some kind of self-starting smart pointer or your own custom string class. You should monitor the interface as defined in std :: string for ease of use.

 class bstr_string { _bstr_t contents; public: bool operator==(const bstr_string& eq); ... ~bstr_string() { // free _bstr_t } }; 

In C ++, you never deal with raw pointers, unless you have an important reason, you always use self-classes. Typically, Microsoft uses source pointers because they want their interfaces to be C compatible, but if you don't care, then don't use raw pointers.

0
source

A simple solution is to simply return a std::string . This implies one dynamic memory allocation, but you will probably get it anyway (since either the user or your function will have to explicitly allocate the allocation)

An alternative would be to give the user the ability to pass to the output iterator into which you enter the string. Then the user is given full control over how and when to select and store the string.

0
source

In the first round, I missed that it was a question in C ++, and not a simple question C. The presence of C ++ in my hand opens up another possibility: a class of control pointer that can be said to be deleted or not.

 class MsgText : public boost::noncopyable { const char* msg; bool shouldDelete; public: MsgText(const char *msg, bool shouldDelete = false) : msg(msg), shouldDelete(shouldDelete) {} ~MsgText() { if (shouldDelete) free(msg); } operator const char*() const { return msg; } }; const MsgText GetDirectShowMessageDisplayText(int messageNumber) { switch(messageNumber) { case EC_ACTIVATE: return MsgText("A video window is being activated or deactivated."); // etc default: { char *msg = asprintf("Undocumented message (%u)", messageNumber); return MsgText(msg, true); } } } 

(I don’t remember if Windows had CRT asprintf , but it's easy enough to rewrite above on top of std::string if that is not the case.)

Note the use of boost :: noncopyable, though - if you copy this type of object, you run the risk of doubling it. Unfortunately, this can cause problems with returning from the Message-pretty-printer function. I'm not sure what the right way to handle this is, I am not really a C ++ guru.

0
source

There is no good answer, but this kludge may be enough.

 const char *GetDirectShowMessageDisplayText(int messageNumber) { switch(messageNumber) { // ... default: { static char defaultMessage[] = "Unexpected notification code #4294967296"; char *pos = defaultMessage + sizeof "Unexpected notification code #" - 1; snprintf(pos, sizeof "4294967296" - 1, "%u", messageNumber); return defaultMessage; } } } 

If you do this, callers should be aware that the string they are returning from GetDirectShowMessageText may be knocked out by a subsequent function call. And this is clearly not safe. But these may be acceptable limits for your application.

-1
source

All Articles