Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assignment of new value to immutable value structs in C++/CLI

It is often recommended to use immutable structs in .NET programming, since using mutable structs sets one up for simple mistakes. However, when I attempt to assign a new value by instantiating a new struct, I get error C3892 in C++ yet the equivalent code in C# has no issue. This is a problem because this prevents me from initializing an array of immutable structs.

The issue is easily worked around by using a readonly property instead of a field, but I would like to know why I cannot do the same thing in C++/CLI as in C#. Am I doing something wrong, or is this simply a limitation (or bug) in C++/CLI? Is there any way to make use of arrays of immutable structs in C++/CLI or must I avoid them?

C++ Header (named "AnnoyingCppBug.h"):

using namespace System;

namespace AnnoyingCppBug {

    public value struct immutableType
    {
        const int Value;

        immutableType(int value)
            : Value(value) {}
    };

    public value struct immutableWorkaround
    {
        property int Value
        {
            int get() { return _value; }
        }

        immutableWorkaround(int value)
            : _value(value) {}
    private:
        int _value;
    };

    public value struct mutableType
    {
        int Value;

        mutableType(int value)
            : Value(value) {}
    };

    public value struct Class1 abstract sealed
    {
        static void Test();
    };
}

C++ Source File:

#include "stdafx.h"

#include "AnnoyingCppBug.h"

namespace AnnoyingCppBug {
    void Class1::Test()
    {
        auto imm1 = immutableType(0);
        auto imm2 = immutableWorkaround(0);
        auto imm3 = mutableType(0);

        imm1 = immutableType(1);    // error C3892: 'arr1': you cannot assign to a variable that is const
        imm2 = immutableWorkaround(1);
        imm3 = mutableType(1);

        // The reason this matters is because I need to initialize an array:
        auto arr = gcnew array<immutableType>(1);
        arr[0] = immutableType(0);  // error C3892: 'arr1': you cannot assign to a variable that is const
    }
}

C# Code that does the same but builds fine:

    struct immutableType
    {
        public readonly int Value;
        public immutableType(int value)
        {
            Value = value;
        }
    }

    static void Test()
    {
        var imm = new immutableType(0);
        imm = new immutableType(1);
        var arr = new immutableType[1];
        arr[0] = new immutableType(1);
    }
like image 665
John Thoits Avatar asked Nov 16 '25 20:11

John Thoits


1 Answers

The answer was provided by Hans Passant in the comments on the question: I mistakenly used the C++ only (not C++/CLI) keyword const as if it meant the same as C# keyword readonly. The correct keyword that will be compiled into CLR equivalently to the C# keyword readonly is "initonly".

The const keyword will only instruct the compiler to generate errors but not ever produce any different CLR byte code. In general, given this revelation, I would recommend not to ever use the const keyword in managed C++ code. I also think that the C++/CLI compiler should generate a warning, but perhaps there are good reasons it does not (after all the compiler isn't meant to be a teacher).

like image 125
John Thoits Avatar answered Nov 19 '25 11:11

John Thoits