Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does it make sense to avoid std::wstring data members in a C++ exception class on modern PC's?

In paragraph "How should I design my exception classes?" in this "Error and Exception Handling" Boost web page, it reads:

[...] 3. Don't embed a std::string object or any other data member or base class whose copy constructor could throw an exception.

I have to define an exception class to represent some form of run-time error on file access, so I was thinking to derive it from std::runtime_error, and add a FileName() attribute to get access to the file name for which the error occurred.

For simplicity sake, my intention was to add a std::wstring data member to store the file name (in Unicode), but the aforementioned suggestion kind of stopped me. So, should I use a simple wchar_t buffer as a data member?

On modern desktop systems (which are my target platforms for this project), is it really important to pay attention to a dynamic string allocation for a file name? What is the likelihood of such allocation to fail? I can understand Boost's suggestion for limited-resource systems like embedded systems, but is it valid also for modern desktop PC's?

//
// Original design, using std::wstring.
//
class FileIOError : public std::runtime_error
{
public:
    FileIOError(HRESULT errorCode, const std::wstring& filename, const char* message)
        : std::runtime_error(message),
          m_errorCode(errorCode),
          m_filename(filename)
    {
    }

    HRESULT ErrorCode() const
    {
        return m_errorCode;
    } 

    const std::wstring& FileName() const
    {
        return m_filename;
    }

private:
    HRESULT m_errorCode; 
    std::wstring m_filename;
};



//
// Using raw wchar_t buffer, following Boost's guidelines.
//
class FileIOError : public std::runtime_error
{
public:
    FileIOError(HRESULT errorCode, const wchar_t* filename, const char* message)
        : std::runtime_error(message),
          m_errorCode(errorCode)
    {
        // Safe string copy
        // EDIT: use wcsncpy_s() with _TRUNCATE, as per Hans Passant's suggestion.
        wcsncpy_s(m_filename, filename, _TRUNCATE);
    }

    HRESULT ErrorCode() const
    {
        return m_errorCode;
    } 

    const wchar_t* FileName() const
    {
        return m_filename;
    }

private:
    HRESULT m_errorCode; 
    wchar_t m_filename[MAX_PATH]; // circa 260 wchar_t's
};
like image 892
Mr.C64 Avatar asked Nov 17 '12 12:11

Mr.C64


People also ask

Should I use string or Wstring?

These are the two classes that you will actually use. std::string is used for standard ascii and utf-8 strings. std::wstring is used for wide-character/unicode (utf-16) strings. There is no built-in class for utf-32 strings (though you should be able to extend your own from basic_string if you need one).

What is std::wstring?

std::to_wstring in c++This function is used to convert the numerical value to the wide string i.e. it parses a numerical value of datatypes (int, long long, float, double ) to a wide string. It returns a wide string of data type wstring representing the numerical value passed in the function.

How do I convert Wstring to CString?

The easiest solution is to use Unicode string literals and std::wstring: wstring z = L"nüşabə"; CString cs(z. c_str()); nameData. SetWindowTextW(cs);

What is std :: string& in C++?

C++ has in its definition a way to represent a sequence of characters as an object of the class. This class is called std:: string. String class stores the characters as a sequence of bytes with the functionality of allowing access to the single-byte character.


1 Answers

What is the likelihood of such allocation to fail?

Pretty low.

Usually for the purpose of code correctness you only really care whether that likelihood is zero or non-zero. Even on a system where the built in ::operator new never fails due to rampant over-commit, consider the likelihood that your code will be used in a program that replaces ::operator new. Or maybe an OS will externally limit the amount of memory a process is permitted to allocate, by ulimit -v or otherwise.

Next consider the consequences of it failing. terminate() is called. Maybe you can live with that, especially since it's unlikely to actually happen.

Basically, do you want your program to even try to exit cleanly with a reasonable error message in the case where you can't allocate memory? If so, write the extra code and accept the limit on the length of the error message. Because Boost is general-purpose library code, it doesn't assume on behalf of its users that they don't want to try.

like image 177
Steve Jessop Avatar answered Nov 04 '22 12:11

Steve Jessop