C++/CLI to C++ Tips and Tricks

C++/CLI to C++ Tips and Tricks

  • Comments 3

In my previous post, Writing Unit Tests in Visual Studio for Native C++, I described the approach I’m using to write unit tests for native C++ code by using C++/CLI, which is C++ code that runs inside the .NET runtime. Because of this “mixed” programming model, there are some techniques you may need to employ between C++ and C++/CLI code.

Class Instance Variables

The instance variables in C++/CLI classes are different from instance variables in native C++, which means you can’t mix the two blindly. For example, you can’t use native C++ classes as instance variables in your test class. The following, for example, will not compile:

public ref class MyFixture
{
MyClass m_instance;
};
 
You’ll get the following error message:

error C4368: cannot define 'm_instance' as a member of managed 'Tests::MyFixture': mixed types are not supported

So how do you deal with this? Instead of using a class as the type, you have to use pointers and then create/destroy the instance in the TestInitialize and TestCleanup code:

public ref class MyFixture
{
[TestInitialize]
void Initialize()
{
m_pInstance = new MyClass();
}



[TestCleanup]
void Cleanup()
{
delete m_pInstance;
}



MyClass *m_pInstance;
};


The methods marked by TestInitialize and TestCleanup run before and after each test method.

Passing a Pointer to an Instance Variable

C++/CLI instance variables have a type of interior_ptr<T> instead of the type you wrote in your code. This makes a difference if you attempt to pass either the address or a reference to this instance variable to a native C++ method or function. For example, given the class above, you might think you could write a call to one of your native methods like this:

p->SomeMethod(&m_pInstance);

Compile this and you’ll see this message:

error C2664: 'Tests::MyFixture::MyTest' : cannot convert parameter 2 from 'cli::interior_ptr<Type>' to 'MyClass **'

This error appears because .NET uses a heap—items on the heap can be moved as a result of garbage collection. In order to send a pointer to a native method/function, you need to “pin” the pointer for the duration of the call, which you can do like this:

cli::pin_ptr<MyClass *> p = &m_pInstance;
SomeMethod(static_cast<MyClass **>(p));

Once the variable p either goes out of scope, or is assigned a new value, the pointer will be free to change again.

When you’re dealing with helper methods in your test code, you can also write this type of code:

Helper(&m_pInstance);
...
void Helper(cli::interior_ptr<MyClass *> ppInstance)
{
**ppInstance = new MyClass();
}

  • A good write-up. Thanks - makes me think I should know more about cli::interior_ptr<>

  • Nothing, but funny typo:

    naïve C++

    btw: good post

  • SHK, thanks. I've fixed that typo...

Page 1 of 1 (3 items)
Leave a Comment
  • Please add 2 and 2 and type the answer here:
  • Post