Question

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?

Was it helpful?

Solution 2

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...

OTHER TIPS

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top