C++/CLI : Why can't I pass Strings by reference? - string

Why doesn't Microsoft's C++/CLI allow me to pass strings by reference? I received the following error:
C3699: '&': cannot use this indirection on type 'System::String'

First of all, there are really two Microsoft-specific C++ dialects for .NET: the older "Managed C++" (Visual Studio 2002 and 2003) and C++/CLI (Visual Studio 2005 and later).
In C++/CLI, System::String^ is a .NET reference to a string; some authors call this a "tracking pointer" to compare and contrast it with a normal C++ pointer. As in C++, you can pass .NET references "by reference", but instead of using &, you use %, as in:
void makeStr(System::String^ %result) {
result = gcnew System::String("abc");
}

Sounds like you are using Managed C++, which is a bastardised C++ used with the .NET Framework.
in Managed C++, I believe the syntax you are looking for is System::String^. The reason for this is that since managed types are garbage collected by .NET Framework, you aren't allowed to create 'regular' references since the GC needs to track all the references to a specific variable to know when it is safe to free it.

It looks like you are using Managed C++. You should use System::String^ instead.

Related

What's the difference between the macros _MANAGED and _cplusplus_cli?

The MS docs (even back in 2005) state for both:
_MANAGED : Defined to be 1 when /clr is specified.
__cplusplus_cli: Defined when compiling with /clr, /clr:pure, or /clr:safe. (...)
So if I'm compiling a C++/CLI module and need to check, which one should I use?
The answer is mentioned here:
both macros are supposed to be defined if the /clr option is
specified. Are you perchance using /clr:oldSyntax? In that case,
you're targeting Managed C++, not C++/CLI
And indeed, when looking at the 2003 docs there is only _MANAGED and there is no C++/CLI there yet.
To answer which one should I use, I'd say it doesn't really matter unless you need to differentiate between oldSyntax and CLI.

Using 'auto' in for each causes C3539 - Why?

I am writing a managed DLL in VC2010 (i.e. /CLR is enabled for a VC++ DLL project). Following code wouldn't compile:
System::Collections::Generic::List<int>^ my_list;
for each(auto elem in my_list)
{
}
It raises error C3539: 'auto': a template-argument cannot be a type that contains 'auto'.
I don't understand the reason. I tried compiling the same in VS2012, and it raises same error (which is not appropriate error).
Why compiler fails to deduce the type for a colleciton? The same type of code would work in C# with var keyword.
First, the most importand point from the comments:
presented code does compile in VS2013 c++/cli dll .net 4.5 (Zee, 2014-05-03)
When you compile C++/CLI, which is the .NET binding for C++, you are using a different feature set of the Microsoft compiler. Whether something works either
when /clr is in effect
or, additionally, when you're using a "managed" construct (as in your code)
has nothing to to with if the "normal", native, MSVC compiler accepts it.
So as for "why": It would simply appear that auto type deduction did not work for the managed handle types in VS2010 and VS2012, but, according to Zee's comment, has then been implemented in VS2013. (A quick Search Engine check didn't find any official statement wrt. this, so I may be wrong.)

Visual C++ Release build - is string getting corrupted when passed across DLL because compiled with different runtime version?

After building in Release mode, I am seeing exceptions which didn't occur in Debug mode. When debugging the release build, it looks like string references are not being passed correctly from the EXE (our application) to the DLL which is receiving the string reference.
Our EXE code looks like this:
string contents = "handle_message(): received=" + msg->encode();
LOG4CXX_DEBUG(logger, contents);
The LOG4CXX_DEBUG is going to log4cxx.dll, whose code looks like this:
CharMessageBuffer& CharMessageBuffer::operator<<(const std::basic_string<char>& msg) {
if (stream == 0) {
buf.append(msg);
} else {
*stream << msg;
}
return *this;
}
Looking at the Call Stack in the debugger, when I navigate down to the frame which has our source, I can see that contents is a valid string with size=583, capacity=838.
In the frame inside the log4cxx.dll (the next frame above in the stack) the string reference shows size=838, capacity=363113231 (and the values are all garbage).
Both our app and log4cxx.dll were compiled on the same machine, using the same runtime settings (/MD), but different versions of Visual Studio. The log4cxx dll was compiled using Visual Studio 2008 and our application was compiled using Visual Studio 2010. Running dumpbin on the 2 objects shows:
Our App (EXE)
MSVCP100.dll
MSVCR100.dll
log4cxx.dll (DLL)
MSVCP90.dll
MSVCR90.dll
Is this problem due to the fact that they are using different runtime versions?
If you pass non-POD (plain old datatypes) between DLL/EXE boundaries (like STL string or CRT FILE pointers) you must use the same shared CRT.
In your case, you must recompile all DLLs/LIBs with the same compiler!
See also: I can pass std::string for a Dll and what i can do with DLL´s?
The implicit question is:"Is there a way to pass data, hopefully using string and other STL containers, to DLLs of another version of visual studio either previous or later than the one that I'm using?".
Aside from using POD, there are probably three approaches: shared memory, sockets( to local host ) and MSMQ. All of these methods require additional extensive programming, but the deeper answer is found in how the interface is changing the input parameter.
I have found a possible solution to the string passing problem on the internet. It removes one layer of corruption; cast a pointer to the container to a uint and pass the uint. Dereference the uint to the pointer and the object is revealed. Beware, auto_ptrs are usually deleted in this process, so don't use them. If the passed object is still offset incorrectly( this happened to me with VS08 passing to a VS13 ), then pass the c_str() of the string instead. It's certainly inelegant, but we need to know all the alternatives. See "HowTo: Export C++ classes from a DLL" in Code Project( Nov 22, 2012 ).

TitleCase In Visual C++

I'm currently trying to find an easy way to convert a Visual (Managed) C++ string to title case.
In VB.NET, you can use either:
StrConv(sampleString, vbProperCase)
or
sampleString = System.Globalization.CultureInfo.CurrentUICulture.TextInfo.ToTitleCase(sampleString)
In C# you use:
sampleString = System.Globalization.CultureInfo.CurrentUICulture.TextInfo.ToTitleCase(sampleString)
How do I do it in Visual C++? Is it something similar that I just can't seem to find?
Check the documentation on TextInfo.ToTitleCase it has examples for Managed C++
If you're talking about managed C++, you can use the same functions as in C#/VB.Net.
If you mean native C++, then:
Pretty certain there's nothing of the sort in the language itself.
AFAIK not in the Win32 API as well.
Your best hope then is to find such a function in some library (I personally can't think of one).

short enums on VC++ 6.0 (or VC++ 2008)?

It would be very convenient to have "short enum" or "char enum" in VC++, as I have seen mentioned elsewhere for GCC etc. Is there some option in VC++ to allow this?
You can use something like
enum name : char
{
values
}
but this is a VC-specific extension. Not sure if there's standardised support for this in VC.

Resources