Adventures with string_view: Making string_view Play Well with ATL/MFC CString

Suppose that you have a C++ code base containing methods and functions that take ATL/MFC CString objects as input parameters, for example:

void DoSomething(const CString& s)

and you want to introduce the use of std::string_view in that code.

Let’s assume that your code base is built using Visual Studio in Unicode mode (Configuration Properties | Advanced | Character Set set to Use Unicode Character Set), which has been the default since Visual Studio 2005. In this case, CString is actually the wchar_t-based CStringW, and the matching std::basic_string_view is the wchar_t-based std::wstring_view.

(Note: It could be possible to convert between Unicode UTF-16 CStringW and UTF-8, and store the UTF-8 encoded text in a std::string object, and take a std::string_view on that, but let’s not make things even more complicated!)

So, you may think of adding a wstring_view overload like this:

void DoSomething(std::wstring_view s)

Unfortunately, that would cause a problem with your pre-existing perfectly compiling code. In fact, if you pass a string literal, like this:

DoSomething(L"Connie");

the C++ compiler now has two options for DoSomething: the initial form that takes a const CString&, and the new one that takes a wstring_view. The C++ compiler has no way to choose which overload to pick, so it emits an error complaining about the ambiguous call to the DoSomething overloaded function.

At this point, you may think of removing the previous CString overload, and only keep the new wstring_view version:

// Removed: void DoSomething(const CString&)
void DoSomething(std::wstring_view s)

OK, now the C++ compiler is happy as there is only one function to pick.

So, problem solved? Nope.  Don’t forget that this is C++! 😊 And things can get more “interesting” when you apparently solved one problem.

For example, in your existing code base you almost certainly have a number CString objects around. For the sake of simplicity, consider this code snippet:

CString name;
DoSomething(name);

This code worked perfectly fine before you added wstring_view, but now the compiler complains! The problem this time is that the C++ compiler cannot find a suitable way to convert from CString to wstring_view. How can you fix that?

Well, you can invoke the CString::GetString method. In fact, this method returns a const wchar_t* raw pointer to the NUL-terminated C-style string associated with the CString object. And wstring_view has a constructor overload that matches this particular case, constructing a view of the NUL-terminated character string passed as input pointer parameter.

This will work:

// name is a CString
DoSomething(name.GetString());

Another important consideration to make is that wstring_view is just a view to a string, so you must pay attention that the pointed-to string is valid for at least all the time you are referencing it via the wstring_view. In other words, pay attention to dangling references and string views that refer to strings that have been deallocated or moved elsewhere in memory.

 

Open Source: Who Pays for It?

Recently I worked on my C++ WinReg library for a couple of hours, adding some useful methods, testing them, and packaging the library for vcpkg distribution.

At a reasonable rate of $150/hour, that would be $300.

And that’s not even counting all the many hours I spent in total on this open-source project.

This library has currently more than 260 stars on GitHub, and many forks. It seems to me it is used by many people.

But who pays for it?

I think there should be some process to allow developers of useful open-source code hosted on GitHub (or on other platforms as well) to be fairly compensated for their work.

Spot the Bug

Consider the following C++ code snippet:

// Assume proper std:: namespace imports and being inside main

string name = "Connie";
for (auto ch : name) {
    ch = toupper(ch);
}

cout << name << '\n';

What will the output be?

“Connie”? “CONNIE”? Other?

The intention of the programmer was clearly to convert the name string to upper case. But, does this code work as expected? If it doesn’t, what’s the cause of the bug, and how can you fix it?

If you don’t know the answers to the above questions, you may be interesting in my Pluralsight course on learning modern C++ from scratch.

Note that Pluralsight is currently running a 33% off limited-time offer, so you can save now clicking on the banner below:

Pluralsight Limited-Time Offer 33% Off

Just a heads up to let you know that Pluralsight is offering a 33% off discount on individual annual Standard or Premium subscriptions for a limited time (3/14-3/18).

Click the banner and save now!

Simplifying Windows Registry Programming with the C++ WinReg Library

WinReg is a modern C++ library I wrote that exposes a high-level public interface to simplify the access to the Windows Registry.

For instance, instead of invoking low-level C-interface APIs like RegOpenKeyEx or RegQueryValueEx, you can simply create an instance of the winreg::RegKey class:

RegKey key(HKEY_CURRENT_USER, L"SOFTWARE\\SomeKey");

and invoke convenient RegKey’s methods like GetStringValue:

wstring s = key.GetStringValue(L"Connie");

Note that this library wraps low-level native Windows C API types into higher-level C++ classes like std::wstring for Registry string values, or std::vector<std::wstring> for multi-string values.

The C++ WinReg library is open source and freely available on GitHub.

Enjoy!