1

I know that value classes don't have an default constructor as the compiler initializes all elements in this class with zero. But arrays are in a value class are not initialized:

value class c_LocationVal
{
public:
  double x, y, z;
  c_LocationVal(double i_x, double i_y, double i_z) {x = i_x; y = i_y; z = i_z;}
};

typedef cli::array<c_LocationVal> arrloc;

value class c_Managed
{
public:
  arrloc^ m_alocTest;

  //c_Managed() { m_alocTest = gcnew arrloc(3); }  --> not permitted

  double funcManaged ()
  {
    return m_alocTest[0].x;  --> error: Object reference not set to an instance of an object
  }
};

I just could cheat and use:

c_Managed(int i) { m_alocTest = gcnew arrloc(3); }

but there must be another solution.
Can someone please tell me how to solve this?

3
  • What you call cheating is actually required in C#. I assume the same rule goes for C++/CLI. Can't you declare a C array of c_LocationVal instead? Commented Jul 19, 2013 at 13:16
  • Unfortunately I can't: I will get the compiler error C2728 when I create a C-array of a managed type, and I will get compiler error C4368 when I create an array of a unmanaged type inside a managed type. And because the main application is a CLR-Winform, I cannot use unmanaged arrays. Commented Jul 19, 2013 at 13:50
  • possible duplicate of How do I specify a fixed-size buffer in C++/CLI? Commented Jul 23, 2013 at 3:02

3 Answers 3

2

The CLR only supports code inside of methods. Compilers emulate the behavior of a member initialization expression by creating a constructor, if necessary, and moving the code for the expression into the constructor.

Which explains why this isn't permitted, your expression requires a parameterless constructor and that's not legal for a value type.

Sure, your trick will work. But in general, you need to de-tune C++ assumptions a bit when you write C++/CLI code. There are no practical differences between a struct and a class in C++. But that's definitely not the case in managed code. Only ever use a value class for very simple types. Requiring initialization heavily tips the choice to a ref class. As does a value type having an array, you'd normally need a deep copy to make that work without accidents. Never fear the heap in C++/CLI, it is very fast.

Sign up to request clarification or add additional context in comments.

5 Comments

I just thought I could avoid implementing a copy constructor or clone method by making the class a value type. But when you say that value types should only be used for very simple constructs to avoid problems, then this is the wrong type for my application and I really need to deal with a ref class plus clone method now.
That's another thing you have to de-tune, the rule of 3 is important in C++. It is not in managed code, you just about never write a copy constructor. The garbage collector removes the need.
I've now come across the same problem again. I need the functionality of a value class, but it must contain an array of the small value class c_LocationVal, so I have to make the superior class a ref class. But that means I need to implement a clone method, thus I cannot 'de-tune' as much as I wanted, or is there another solution to it?
Yet again something to de-tune. C++ only has value classes, the preferred type in a managed program is a reference type class. Only ever use a value type for very small structs, no more than 16 bytes. There is no built-in support for cloning reference types, you simply add a CopyTo() method to make your own deep copy.
Yet again something to de-tune. C++ only has value classes, the preferred type in a managed program is a reference type class. Only ever use a value type for very small structs, no more than 16 bytes. Cloning a reference type object is supported by the inherited Object::MemberwiseClone() but that's a shallow copy and very rarely useful. Simply add a CopyTo() method to make your own deep copy. There's otherwise nothing that stops you from creating a copy constructor as long as only C++/CLI code uses the class.
1

A value class is always initialized with "null/0". So a managed reference in a value class will also always be initialized to "null". If you want to have a special initialization, then you only have the solution, you were pointing out: You need to create a special constructor which has some parameters to "initialize" the value class correctly.

The question is: Do you really need a value class which contains a managed reference??? Normally this should also be a ref class.

Also, what happens, if the value class is copied? What should happen with the reference? It will also directly copied! Is this intended? The goal of a value class is to provide a "real" copy! In your case it will not "fully copied"...

Pleas re-think if a value class is the best solution for your data storage...

2 Comments

So because the array is a reference type, I should not use it in a value class? And the array reference is copied but not the array content? This makes sense. I really should start the weekend now. ;-)
If he embeds the array directly inside the value class, instead of a reference, it will have the value copy semantic he's looking for.
0

Switch the public field to a property, and do lazy initialization when the property is retrieved.

value class c_Managed
{
private:
  arrloc^ m_alocTest;

public:
  arrloc^ AlocTest
  {
    arrloc^ get()
    {
      if(m_alocTest == nullptr)
      {
        msclr::lock(c_Managed::typeid)
        if(m_alocTest == nullptr)
          m_alocTest = gcnew arrloc(3);
      }

      return m_alocTest;
    }
  }

  double funcManaged ()
  {
    return AlocTest[0].x;
  }
};

The lock for the lazy initialization isn't ideal, but it's just about the only thing to lock on: this is a value type, so locking would box it and the lock would be on the box, not on the object itself. Since it's a value type, providing any reference type as a field to lock on would give a null reference, just like the array, so there's no help there. The only thing I can think to lock on is the type object itself for this type.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.