Cannot assign to an element of an initonly array? - c++-cli

It seems commonly thought that C++/CLI's initonly is the equivalent of C#'s readonly keyword. However, the following:
ref class C {
C();
void Method();
initonly array<int>^ m_array;
};
C::C() {
m_array = gcnew array<int>(10);
}
void C::Method() {
m_array[0] = 5; // Fails with C3893
}
The full error is "'C::m_array': l-value use of initonly data member is only allowed in an instance constructor of class 'C'".
The error message seems strange as I'm not using m_array as the target of an assignment, this is the equivalent of writing
m_array->SetValue(5, 0);
which incidentally compiles fine and does the same thing.
Is this bugged in C++/CLI or by design? By the way, is there any performance penalty to using Array::SetValue vs using the accessor?
A similar (but not identical) case was reported and apparently filed as a bug for VS2008: http://bytes.com/topic/net/answers/847520-initonly-but-not-bug-vc-2008-clr . I'm using Visual Studio 2012.

Yes, that's a bug. It's enforcing something which is not implied by the .NET type system, and the enforcement is ineffective.
But don't use Array::SetValue, which involves boxing and is not type safe. You can just do:
auto array = m_array; // another handle to same array
array[0] = 5;

Related

Which programming language statically check the length of variable-length classes?

Which statically typed programming language exist where the length of arrays, lists, ... is statically inferred and checked? Consider the following working C# example, where this would be useful:
using System.IO;
using System;
using System.Diagnostics;
using System.Linq;
public class Program
{
public static void Main()
{
string[] arrayOfStrings1 = { "the", "quick", "brown", "fox", "jumps" };
var arrayOfStrings2 = functionOnArray(arrayOfStrings1);
for (int i = 0; i < arrayOfStrings1.Length; i++){
var string1 = arrayOfStrings1[i];
var string2 = arrayOfStrings2[i];
// do anything here
}
}
static string[] functionOnArray(string[] arrayOfStrings){
return arrayOfStrings.Skip(1).ToArray();
}
}
This fails at iteration 5, as the arrayOfStrings2.Length is only 4:
[System.IndexOutOfRangeException: Index was outside the bounds of the array.]
at Program.Main() :line 14
If the language could check beforehand that arrayOfStrings2.Length = arrayOfStrings1.Length - 1, it could know before runtime, that the loop will fail. This would prevent some runtime errors and thus make programming easier.
About the possibility of checking this before runtime:
C# already checks before runtime if a nullable variable has been checked for nullability before it can be cast to the non-nullable version. Simply checking this in an if-condition is sufficient, so it somehow infers before runtime the result of a a function (here the if-condition) on the possible values of a variable. This could be implemented the same way for statically checking the length of variables.
Yes, this is possible, it's called "Dependent types". There are academic languages available that support this, for instance Idris.
I don't believe it's available in any commercial main stream languages.

In Managed C++, what is the proper way to define a static singleton instance in a class?

Jumping to Visual Studio 2015 from Visual Studio 2013, I've noticed some differences in how static self-instances in managed C++ classes are accepted by the compiler. Consider these two examples:
Method 1:
public ref class CResourceManager
{
public:
static property CResourceManager^ Instance
{
CResourceManager^ get() { return %m_Instance; }
}
private:
static CResourceManager m_Instance;
};
Method 2:
public ref class CResourceManager
{
public:
static property CResourceManager^ Instance
{
CResourceManager^ get() { return m_Instance; }
}
private:
static CResourceManager^ m_Instance = gcnew CResourceManager;
};
Method 1 used to work on 2013, but it's failing to compile on 2015. I unfortunately do not have the exact compiler error handy, but it was one of those "Missing semicolon before variable name" errors, basically saying it couldn't find the type CResourceManager (pointing to the static variable declaration).
So on to my questions:
Is method 1 supposed to work or be valid in managed C++?
Why would the second method work in 2015, but not the first (i.e. what are the differences)?
Which method is the proper way to accomplish the end goal?
Method 2 is the proper way to do it. The code you have listed is the equivalent of the C# idiom.
Method 1 is a bit unusual.
The lack of a ^ on a declaration would normally mean that the variable is not allocated on the managed heap. However, since it's a static class member, I'm not sure where it actually gets created.
% is normally used for declaring tracking references, the equivalent of passing a variable by ref or out in C#. To be honest, I didn't think that applying % to a variable without either ^ or % and taking the result as a ^ was even valid. (Though considering the 2015 compiler rejects it, it may not be.)
Even if Method 1 is valid, I'd still go with Method 2: The storage location of m_Instance and how it's returned are both plain, common, and easy to understand. This beats having to think about how the code works any day.

pin_ptr Alternative to (void**) using reinterpret_cast or static_cast?

Is there an alternative to using the following?
class IGraphBuilder;
public ref class Device
{
private:
IGraphBuilder* pGraphBuilder;
public:
void Configure()
{
pin_ptr<IGraphBuilder*> ppGraphBuilder = &pGraphBuilder;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph,
NULL,
CLSCTX_INPROC,
IID_IGraphBuilder, (void**)ppGraphBuilder);
reinterpret_cast(ppGraphBuilder) compiles but I'm a bit confused if this is correct for this case.
If this wasn't C++/CLI (where &NativeMember actually means interior_ptr<Type>(NativeMember)) I would simply use static_cast<void**>(&pGraphBuilder) but even after correctly casting to pin_ptr the following doesn't compile
pin_ptr<IGraphBuilder*> ppGraphBuilder = &pGraphBuilder;
static_cast<void**>(ppGraphBuilder)
Is there any solution or am I forced to use (void**) because pin_ptr is weird?
reinterpret_cast (and thus C cast) is potentially not ok, although it may work due to the allegedly trivial layout of pin_ptr. Indeed you have to call the conversion operator from cli::pin_ptr<IGraphBuilder*> to IGraphBuilder** first (hence the complain from the compiler).
reinterpret_cast<void**>(static_cast<IGraphBuilder**>(ppGraphBuilder))
is correct. You may want to introduce a intermediary variable of type IGraphBuilder** first:
pin_ptr<IGraphBuilder*> p = &pGraphBuilder;
IGraphBuilder** ppGraphBuilder = p;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph,
NULL,
CLSCTX_INPROC,
IID_IGraphBuilder, reinterpret_cast<void**>(p));

c++/cli reference to property

Well, I haven't yet found something that says this is impossible, though I'm starting to think it might be. Can you make this work?
using namespace System;
template <typename T>
void unset(Nullable<T>& var) { var = Nullable<T>(); }
void unset(String^% var) { var=nullptr; }
//this is really a C# class in my situation, so I can't change its types
public ref class Foo
{
public:
property Nullable<Decimal> Dec;
property Nullable<int> Num;
property String^ Str;
};
int main()
{
Foo^ foo = gcnew Foo;
foo->Dec = Decimal(1.2);
foo->Num = 3;
foo->Str = "hi";
unset(foo->Dec);
unset(foo->Num);
unset(foo->Str);
Console::WriteLine(foo->Dec);
Console::WriteLine(foo->Num);
Console::WriteLine(foo->Str);
}
Update: unset is called from a code-generating macro which is called on about 50 params. I'd prefer not to have to go make varieties of the macro for each type.
It isn't possible. Setting a property requires calling the property setter function. There is no way to guess for the called method that it needs to call a function vs can assign the passed variable pointer. If you really want to do this then pass a delegate.
There is actually one .NET language that supports it, VB.NET generates code like this:
T temp = obj->prop;
func(temp)
obj->prop = temp;
There is however a dreadful aliasing problem with that, quite undebuggable. This goes belly up in the (rare) case where func() also uses the property. This is otherwise the way you'd work around the limitation, explicitly in your own code.
Beware that your code is wrong, possibly intentional, you are passing a C++ & reference, not a managed % interior pointer. The compiler is going to bitch about that, you can't create references or pointers to managed objects. They move. Unless the reference is to a variable on the stack. It doesn't otherwise change the answer.
For those who may end up here wondering how I got on with this, I ended up being lucky that the class I was working with was an LLBLGen Entity, so I was able to replace
unset(re->var);
with
{ SD::LLBLGen::Pro::ORMSupportClasses::IEntityField2^ f = re->Fields[#var]; \
if (f->IsNullable) \
f->CurrentValue = nullptr; }

AutoPtr in C++/CLI mixed mode

I have a C++/CLI wrapper around native .lib and .h files. I use the AutoPtr class pretty extensively in the wrapper class to manage the unmanaged objects I create for wrapping. I have hit a roadblock with the copy constructor/assignment operator.
Using the AutoPtr class from Mr. Kerr: http://weblogs.asp.net/kennykerr/archive/2007/03/26/AutoPtr.aspx
He suggests the following(in the comments) to recreate the behavior of the assignment operator:
SomeManagedClass->NativePointer.Reset(new NativeType);
Which I believe is true. But when I compile my code:
ByteMessageWrap (const ByteMessageWrap% rhs)
{
AutoPtr<ByteMessage> m_NativeByteMessage(rhs.m_NativeByteMessage.GetPointer());
};
ByteMessageWrap% operator=(const ByteMessageWrap% rhs)
{
//SomeManagedClass->NativePointer.Reset(new NativeType);
if (this == %rhs) // prevent assignment to self
return *this;
this->m_NativeByteMessage.Reset(rhs.m_NativeByteMessage.GetPointer());
return *this;
};
-- I get the following errors:
error C2662:
'WrapTest::AutoPtr::GetPointer' :
cannot convert 'this' pointer from
'const WrapTest::AutoPtr' to
'WrapTest::AutoPtr %'
Has anyone experienced similar issues?
For further background on the answer, I removed the "const" keyword from the signature. I know that is not smiled upon in terms of code correctness for a copy ctor, but the CLR doesn't like it at all -- sort of belies the CLR at its core with memory management.
I wonder if it's possible to leave the const in the signature and then use GCHandle or pin_ptr to make sure memory doesn't move on you while performing the copy?
Looking at Kenny Kerr's AutoPtr, it transfers ownership in its constructor -- essentially a "move" constructor rather than a copy constructor. This is analogous with std::auto_ptr.
If you really want to transfer ownership from rhs to this (i.e. leave rhs without it NativeByteMessage), you need to change your copy ctor into a move ctor.
Also, you need to use initialization syntax;
// warning - code below doesn't work
ByteMessageWrap (ByteMessageWrap% rhs)
: m_NativeByteMessage(rhs.m_NativeByteMessage); // take ownership
{
}
ByteMessageWrap% operator=(ByteMessageWrap% rhs)
{
//SomeManagedClass->NativePointer.Reset(new NativeType);
if (this == %rhs) // prevent assignment to self
return *this;
m_NativeByteMessage.Reset(rhs.m_NativeByteMessage.Release());
return *this;
}