C++ Is Not C#!

And it’s not Java either.

Over the last 12 years I coded first in Java and then in C#. After switching back to coding in C++, I have sometimes written code that works perfectly if translated to Java or C#, but is full of bugs in C++. I will use the following C++ program as a starting point and then refactor it to show a number of problems:

#include <cstdint>
#include <iostream>

struct A
{
 uint32_t* pIntValue;
 float floatValue;
 float* pFloatValue;
};

void printA(const A& a)
{
 std::cout << "intValue: " << *a.pIntValue << ", floatValue: " << a.floatValue;
 std::cout << ", *pFloatValue: " << *a.pFloatValue <<'\n';
}

int main()
{
 uint32_t val1 = 6;
 A anA;
 anA.pIntValue = &val1;
 anA.floatValue = 100.3F;
 anA.pFloatValue = &anA.floatValue;
 printA(anA);
 std::cout << "Press a character key, then Enter to terminate\n";  
 char c;  
 std::cin >> c;
 return 0;
}

Running this program gives this output:

*pIntValue: 6, floatValue: 100.3, *pFloatValue: 100.3

as expected. Now I will factor out the creation and setting of the A struct (anA). I create a new function called getA:

A& getA(uint32_t anInt)
{
	float aFloat = 100.3F;
	A a;
	a.pIntValue = &anInt;
	a.floatValue = aFloat;
	a.pFloatValue = &aFloat;
	return a;
}

and modify main to call it:

int main()
{
	uint32_t val1 = 6;
	A anA = getA(val1);
	printA(anA);
	std::cout << "Press a character key, then Enter to terminate\n";
 	char c;
 	std::cin >> c;
	return 0;
}

If I wrote the equivalent code in C# or in Java, I should get the same result as above. But running this C++ program produces:

*pIntValue: 13630244, floatValue: 100.3, *pFloatValue: -1.07374e+08

which is obviously not what I wanted. How many bugs can you find? Hint: there are at least 3.

And here they are:

  1. getA returns a reference to the A struct created inside the function. In this specific program that is not a problem, but will probably be in more complex programs. At least the VC++ compiler warns about it.
  2. The argument is passed into getA by value. This makes a copy on the stack of the value being passed in. Once the program returns from getA, the stack pointer is repositioned to before the call to getA, and any storage in the stack may be overwritten in the next function call.
  3. aFloat is defined inside getA and is therefore stored on the stack. getA stores the value of aFloat in the structure, and also stores the address of aFloat in the structure. We have the same problem here as for the argument passed by value: after getA returns, the value on the stack can be overwritten, and therefore, the value pointed to will not be correct.

We see the results in the output.

Ok, so why is there no problem in C# or Java? Every variable is a reference counted object, even integer and float variables. So, for example, in getA, aFloat is created as an object on the heap and its reference count is set to 1. When pFloatValue is set, the reference count is incremented. Upon return from getA, the reference count for aFloat is decremented, but the count is not 0, so aFloat still exists on the heap, and therefore the address is still valid. Similarly, arguments to functions are passed as references with the reference count being incremented, and not as copies. Setting pIntValue in the struct again increments the reference count. Both anInt and aFloat remain greater than 0 until anA in main is destroyed. Only then do the reference counts for anInt and aFloat get reduced to 0 and become invalid.

So, let’s fix up the code:

A getA(uint32_t& anInt, float& aFloat)
{
	A a;
	a.pIntValue = &anInt;
	a.floatValue = aFloat;
	a.pFloatValue = &aFloat;
	return a;
}

int main()
{
	uint32_t val1 = 6;
	float aFloat = 100.3F;
	A anA = getA(val1, aFloat);
	printA(anA);
	std::cout << "Press a character key, then Enter to terminate\n";
 	char c;
 	std::cin >> c;
	return 0;
}

Note that I made the following changes:

  1. The struct, a, defined in the function is now returned by value;
  2. The definition of aFloat is moved to main.
  3. Both the integer and float values are passed into getA as references. This ensures that the addresses remain valid even on return from getA.

The output from the program is:

*pIntValue: 6, floatValue: 100.3, *pFloatValue: 100.3

as it was before the refactoring.

These problems showed up a lot in my code after I had returned to C++, but at least I have learned where to look.

Vulkan with wxWidgets

Alexander Overvoorde wrote a good tutorial for programming Vulkan; this is available at vulkan-tutorial.com. In the tutorial, he used GLFW as the windowing system. This is fine if your application uses one main window with no adornments such as menus and status bars, and no additional windows.

I have modified the Hello Triangle example to use wxWidgets. This corresponds to the code up to the end of the Drawing a triangle section of the tutorial. The source code of my wxWidgets version is available on GitHub.

Here is a description of the changes:

  1. HelloTriangleApplication code is split among VulkanTutorialApp, VulkanWindow, and VulkanCanvas. The vast majority of the code is placed in VulkanCanvas. Specifically, the code in HelloTriangleApplication::run is split into two parts:
    • The line:
      mainloop()

      is handled automatically by VulkanTutorialApp, and to some extent by VulkanWindow.

    • The functionality in initWindow and initVulkan are performed in the VulkanCanvas constructor.
  2. The HelloTriangleApplication::drawFrame code is placed in VulkanCanvas::OnPaint.
  3. The HelloTriangleApplication::onWindowResized code is placed in VulkanCanvas::OnResize. wxWindow::RefreshRect must be called to ensure that the canvas is redrawn every time the window is resized. Calling wxWindow::Refresh or wxWindow::Updateonly causes a redraw to occur when the window grows in size, not when shrinking is size.
  4. Two changes were made regarding exceptions:
    • In the tutorial code, runtime_error exceptions are thrown whenever Vulkan errors are encountered. These are replaced with a new exception type called VulkanException which provides information about the actual Vulkan error that was encountered.
    • The tutorial code simply outputs text messages to std::cout. Because the wxVulkanTutorial code is Windows-based, there is no console to output the messages to, so they are output to a wxMessageBox. This was discussed previously in the post C++ Exceptions and wxWidgets.
  5. The tutorial code contains a templated class called VDeleter. This class automatically handles the destruction of various Vulkan handles. I have not included this class in wxVulkanTutorial. Instead, I destroy the handles in the VulkanCanvas destructor.

Have fun with it.

Generating enum class Documentation with Doxygen

Doxygen is the defacto standard for generating API documentation in C++. Documentation on how to comment code to produce your API documentation is generally good, but there are places where the Doxygen documentation is somewhat lacking. I recently ran across one of these cases: documenting enum class enumerations. There is no mention whatsoever in the Doxygen documentation of how to document enum class. enum is documented, but following the methods shown for it may cause problems.

To illustrate the problems, look at the following code. Note that Enum2, Enum2, and Enum3 all have a value called e2.

namespace ns {
    struct A
    {
        enum class Enum1 {
            e1,
            e2
        };

        enum class Enum2 {
            e3,
            e2
        };

        enum class Enum3 {
            e2
        }
    };
}

Trying the following:

/// This is Enum1
/// \var e1
/// This is Enum1::e1
/// \var e2
/// This is Enum1::e2
enum class Enum1 {
    e1,
    e2
};

and so forth, produces this output:

enum1

You should note three things:

  1. The documentation for  Enum1::e2, Enum2::e2, and Enum3::e2 are all placed together in the documentation for Enum1::e2.
  2. There is no documentation for Enum3. This is because there is only one enumeration value, Enum3::e2, which is included in the documentation for Enum1::e2.
  3. The descriptions for Enum1, Enum2, and Enum3 are not placed as descriptions for the enumerations, but rather as part of the documentation for the values.

The only correct way to document enumeration class values is to not use the special \var command, but to place the documentation inline as follows:

enum class Enum2 {
    e3,     ///< This is Enum2::e3
    e2      ///< This is Enum2::e2
}

If you need multiple lines to describe a value, start the documentation on the line below the value, not on the same line. If you start on the same line as the value, that line will be placed last in the description for the value. This will be shown in the final example.

The special command, \enum, should only be used if the description of the enum class is placed after the enum class is defined. To switch back to placing the description before the next enum class, you must use the \enum special command before that description as well.

Here is an example that shows each of these changes. Firstly, note that there is a description for each enumeration. Secondly, each value is correctly described, except Enum2::e3, where the second line of the description in the header file is placed first in the documentation. This is because the first line of the description was placed on the same line as the enumeration value.

namespace ns {
    /// Description of struct A
    struct A
    {
        /// This is enumeration Enum1
        enum class Enum1 {
            e1,     ///< This is Enum1::e1
            e2      ///< This is Enum1::e2
        };

        enum class Enum2 {
            e3,     ///< This is Enum2::e3.
            ///< Second line of Enum2::e3
            e2
            ///< First line of Enum2::e2 description.
            ///< Second line of Enum2::e2 description
            ///<
            ///< Third line of Enum2::e2 description
        };
        /// \enum Enum2
        /// This is enumeration Enum2

        /// \enum Enum3
        /// This is enumeration Enum3
.        enum class Enum3 {
            e2      ///< This is Enum3::e2
        };
    };
}

enum2