Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    HashMap operator = cannot access private member

    Cinema 4D SDK
    r19 c++
    2
    5
    652
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • C4DSC
      C4DS
      last edited by C4DS

      Hello,

      While implementing plugins in the past I managed to understand that for using a specific class into maxon::BaseArray one had to provide own copy and assignment functionality, instead of the default generated ones. This related to the fact that MAXON_DISALLOW_COPY_AND_ASSIGN needed to be defined.
      In R20 and above the issue I experience does not seem to exist.
      This probably due to changes in the SDK related to maxon::HashMap::Insert replacing the former maxon::HashMap::Put ... I haven't digged deeper, so it is just a thought I have.

      However, with R16 .. R19, I experience a 'TestClass::operator = ': cannot access private member declared in class 'TestClass'.

      This has been brought up quite a while, back in the days before R20, but mostly when using maxon::BaseArray.
      So, now that I am using maxon::HashMap I encounter an issue I don't seem to know the solution for.

      I do have provided the necessary constructors and operators to make it work for the maxon::BaseArray, but I seem to miss something for the maxon::HashMap. And I just seem not to be able to put my finger on ...

      #include "c4d.h"
      
      class TestClass
      {
      	MAXON_DISALLOW_COPY_AND_ASSIGN(TestClass)
      
      private:
      	Bool mBool;
      	Int32 mInt32;
      
      public:
      	TestClass() : mBool(false), mInt32(0) {}
      	~TestClass() {}
      
      	// move constructor
      	TestClass(TestClass&& src) :
      		mBool(std::move(src.mBool)),
      		mInt32(std::move(src.mInt32))
      	{}
      
      	// move assignment operator
      	MAXON_OPERATOR_MOVE_ASSIGNMENT(TestClass);
      
      	// copy
      	MAXON_WARN_UNUSED maxon::Result<void> CopyFrom(const TestClass& src)
      	{
      		mBool = src.mBool;
      		mInt32 = src.mInt32;
      		return maxon::OK;
      	}
      };
      
      void Test()
      {
      	// using BaseArray does compile
      
      	maxon::BaseArray<TestClass> arrayTestClass;
      
      	TestClass newitem;
      	arrayTestClass.Append(newitem);
      
      	// using HashMap does not compile
      	// operator = cannot acces private member
      
      	maxon::HashMap<Int32, TestClass> mapTestClass;
      
      	TestClass newitem2;
      	mapTestClass.Put(0, newitem2);
      }
      
      Error	C2248	'TestClass::operator =' : cannot access private member declared in class 'TestClass'	
      

      Now, I do understand the fact that the assignment operator is private for the hashmap data structure, and thus the reason for the error being reported. I just don't see what is missing in my TestClass?

      1 Reply Last reply Reply Quote 0
      • C4DSC
        C4DS
        last edited by

        Hmm ... seems I have been doing it wrong all those years ???

        According to this post in the legacy forum, the disallowing of copy and assignment isn't to be done in the class that is being used INSIDE a maxon::BaseArray (or maxon::HashMap).
        It's the class that holds such basearray or hashmap as member which will need to provide the copy and assignment implementation.

        I need to try this.

        1 Reply Last reply Reply Quote 0
        • C4DSC
          C4DS
          last edited by C4DS

          Still getting nowhere ...

          Following code uses only maxon::BaseArray and all compiles fine.

          #include "c4d.h"
          
          class ValuePair
          {
          private:
          	Int32 mValue1;
          	Int32 mValue2;
          
          public:
          	ValuePair() : mValue1(0), mValue2(0) {}
          	~ValuePair() {}
          };
          
          class ValuePairArray
          {
          	MAXON_DISALLOW_COPY_AND_ASSIGN(ValuePairArray)
          
          private:
          	maxon::BaseArray<ValuePair> mBaseArrayValues;
          
          public:
          	ValuePairArray() {}
          	~ValuePairArray() {}
          
          	// move constructor
          	ValuePairArray(ValuePairArray&& src) :
          		mBaseArrayValues(std::move(src.mBaseArrayValues))
          	{}
          
          	// move assignment operator
          	MAXON_OPERATOR_MOVE_ASSIGNMENT(ValuePairArray);
          
          	// copy
          	MAXON_WARN_UNUSED maxon::Result<void> CopyFrom(const ValuePairArray& src)
          	{
          		if (mBaseArrayValues.CopyFrom(src.mBaseArrayValues) == maxon::FAILED)
          			return maxon::OutOfMemoryError(CREATE);
          		return maxon::OK;
          	}
          };
          
          class StorageWrapper
          {
          	MAXON_DISALLOW_COPY_AND_ASSIGN(StorageWrapper)
          
          public:
          	StorageWrapper() {}
          	~StorageWrapper() {}
          
          	// move constructor
          	StorageWrapper(StorageWrapper&& src) :
          		mBaseArray(std::move(src.mBaseArray))
          	{}
          
          	// move assignment operator
          	MAXON_OPERATOR_MOVE_ASSIGNMENT(StorageWrapper);
          
          	// copy
          	MAXON_WARN_UNUSED maxon::Result<void> CopyFrom(const StorageWrapper& src)
          	{
          		if (mBaseArray.CopyFrom(src.mBaseArray) == maxon::FAILED)
          			return maxon::OutOfMemoryError(CREATE);
          		return maxon::OK;
          	}
          
          	maxon::BaseArray<ValuePairArray> mBaseArray;
          };
          
          void Test()
          {
          	ValuePairArray newitem;
          
          	// using the ValuePairArray class directly
          	maxon::BaseArray<ValuePairArray> arrayOfValuePairArray;
          
          	arrayOfValuePairArray.Append(newitem);
          
          
          	// using the ValuePairArray class via a storage wrapper class
          	StorageWrapper storageHelper;
          	
          	storageHelper.mBaseArray.Append(newitem);
          }
          
          

          Following code continues on the previous code, but adds a maxon::HashMap.
          And results in compiler error for the private assignment operator being inaccessible.
          I just don't get it.

          
          #include "c4d.h"
          
          class ValuePair
          {
          private:
          	Int32 mValue1;
          	Int32 mValue2;
          
          public:
          	ValuePair() : mValue1(0), mValue2(0) {}
          	~ValuePair() {}
          };
          
          class ValuePairArray
          {
          	MAXON_DISALLOW_COPY_AND_ASSIGN(ValuePairArray)
          
          private:
          	maxon::BaseArray<ValuePair> mBaseArrayValues;
          
          public:
          	ValuePairArray() {}
          	~ValuePairArray() {}
          
          	// move constructor
          	ValuePairArray(ValuePairArray&& src) :
          		mBaseArrayValues(std::move(src.mBaseArrayValues))
          	{}
          
          	// move assignment operator
          	MAXON_OPERATOR_MOVE_ASSIGNMENT(ValuePairArray);
          
          	// copy
          	MAXON_WARN_UNUSED maxon::Result<void> CopyFrom(const ValuePairArray& src)
          	{
          		if (mBaseArrayValues.CopyFrom(src.mBaseArrayValues) == maxon::FAILED)
          			return maxon::OutOfMemoryError(CREATE);
          		return maxon::OK;
          	}
          };
          
          class StorageWrapper
          {
          	MAXON_DISALLOW_COPY_AND_ASSIGN(StorageWrapper)
          
          public:
          	StorageWrapper() {}
          	~StorageWrapper() {}
          
          	// move constructor
          	StorageWrapper(StorageWrapper&& src) :
          		mBaseArray(std::move(src.mBaseArray)),
          		mHashMap(std::move(src.mHashMap))
          	{}
          
          	// move assignment operator
          	MAXON_OPERATOR_MOVE_ASSIGNMENT(StorageWrapper);
          
          	// copy
          	MAXON_WARN_UNUSED maxon::Result<void> CopyFrom(const StorageWrapper& src)
          	{
          		if (mBaseArray.CopyFrom(src.mBaseArray) == maxon::FAILED)
          			return maxon::OutOfMemoryError(CREATE);
          		if (mHashMap.CopyFrom(src.mHashMap) == maxon::FAILED)
          			return maxon::OutOfMemoryError(CREATE);
          		return maxon::OK;
          	}
          
          	maxon::BaseArray<ValuePairArray> mBaseArray;
          	maxon::HashMap<Int32, ValuePairArray> mHashMap;
          };
          
          void Test()
          {
          	ValuePairArray newitem;
          	Int32 key = 1;
          
          	// using the ValuePairArray class directly
          	maxon::BaseArray<ValuePairArray> arrayOfValuePairArray;
          	maxon::HashMap<Int32, ValuePairArray> mapOfValuePairArray;
          
          	arrayOfValuePairArray.Append(newitem);
          	mapOfValuePairArray.Put(key, newitem);
          
          
          	// using the ValuePairArray class via a storage wrapper class
          	StorageWrapper storageHelper;
          	
          	storageHelper.mBaseArray.Append(newitem);
          	storageHelper.mHashMap.Put(key, newitem);
          }
          
          
          Error	C2248	'ValuePairArray::operator =' : cannot access private member declared in class 'ValuePairArray'
          
          1 Reply Last reply Reply Quote 0
          • r_giganteR
            r_gigante
            last edited by

            Hi Daniel, first and foremost I terribly apologize for coming so late here.

            With regard to your question, I've a few comments:

            • maxon::BaseArray can store instance derived by classes that are not necessarily defined using MAXON_DISALLOW_COPY_AND_ASSIGN: the BaseArray Manual present in the Classes section four different cases of classes.
            • in < R20 the maxon::HashMap was not designed to manage instances derived by classes defined with the MAXON_DISALLOW_COPY_AND_ASSIGN: if you want to manage such instances in HashMap in R19 or older it's likely you have to store the instances in the stack and store the references in the HashMap.
              That said, in R19, you can either decide to use a class not defined with MAXON_DISALLOW_COPY_AND_ASSIGN with both maxon::BaseArray and maxon::HashMap or if you want to use the MAXON_DISALLOW_COPY_AND ASSIGN then you've to take care of storing references in the R19 HashMap.
            class TestClassDisallowCopyAndAssign
            {
            	MAXON_DISALLOW_COPY_AND_ASSIGN(TestClassDisallowCopyAndAssign)
            	
            private:
            	Bool _mybool;
            	Int32 _myint;
            	
            public:
            	
            	TestClassDisallowCopyAndAssign() {}
            	TestClassDisallowCopyAndAssign(const Bool boolVal, const Int32 intVal)
            	{
            		_mybool = boolVal;
            		_myint = intVal;
            	}
            	~TestClassDisallowCopyAndAssign() {}
            	
            	// move constructor
            	TestClassDisallowCopyAndAssign(TestClassDisallowCopyAndAssign&& src)
            	{
            		_mybool = std::move(src._mybool);
            		_myint = std::move(src._myint);
            	}
            
            	// move assignment operator
            	MAXON_OPERATOR_MOVE_ASSIGNMENT(TestClassDisallowCopyAndAssign);
            
            	// copy
            	Bool CopyFrom(const TestClassDisallowCopyAndAssign& src)
            	{
            		_mybool = src._mybool;
            		_myint = src._myint;
            		return true;
            	}
            	Bool GetBool() const { return _mybool; }
            	Int32 GetInt32() const { return _myint; }
            };
            
            class TestClass
            {
            	
            private:
            	Bool _mybool;
            	Int32 _myint;
            	
            public:
            	TestClass() {}
            	TestClass(const Bool boolVal, const Int32 intVal)
            	{
            		_mybool = boolVal;
            		_myint = intVal;
            	}
            	~TestClass() {}
            	TestClass(const TestClass& src) : _mybool(src._mybool), _myint(src._myint) { }
            	Bool GetBool() const { return _mybool; }
            	Int32 GetInt32() const { return _myint; }
            };
            
            ...
            	
            	// using BaseArray with a instances that can be copied
            	maxon::BaseArray<TestClass> arrayTestClass;
            	
            	TestClass item1 = TestClass(false, 1);
            	TestClass item2 = TestClass(true, 2);
            	TestClass item3 = TestClass(false, 3);
            	TestClass item4 = TestClass(true, 4);
            	
            	arrayTestClass.Append(item1);
            	arrayTestClass.Append(item2);
            	arrayTestClass.Append(item3);
            	arrayTestClass.Append(item4);
            	
            	for (Int32 i = 0; i < arrayTestClass.GetCount(); i++)
            	{
            		GePrint("arrayTestClass[" + String::IntToString(i) + "]: "+String::IntToString(arrayTestClass[i].GetBool())+"/"+String::IntToString(arrayTestClass[i].GetInt32()));
            	}
            	
            	// using HashMap with a instances that can be copied
            	maxon::HashMap<Int32, TestClass> mapTestClass;
            	
            	mapTestClass.Put(404, item1);
            	mapTestClass.Put(101, item2);
            	mapTestClass.Put(303, item3);
            	mapTestClass.Put(202, item4);
            	for (Int32 i = 0; i < mapTestClass.GetCount(); i++)
            	{
            		const Int32 k = mapTestClass.GetNonEmptyBucket(i)->GetKey();
            		const TestClass value = mapTestClass.GetNonEmptyBucket(i)->GetValue();
            		GePrint("mapTestClass["+String::IntToString(i)+"]: key["+String::IntToString(k)+"], value["+String::IntToString(value.GetBool())+"/"+String::IntToString(value.GetInt32())+"]");
            	}
            	
            	Int32 key = 101;
            	GePrint("mapTestClass@Key[" + String::IntToString(key)+"]: "+ String::IntToString(mapTestClass.FindEntry(key)->GetValue().GetBool()) + "/" + String::IntToString(mapTestClass.FindEntry(key)->GetValue().GetInt32()));
            	
            	key = 303;
            	GePrint("mapTestClass@Key[" + String::IntToString(key)+"]: "+ String::IntToString(mapTestClass.FindEntry(key)->GetValue().GetBool()) + "/" + String::IntToString(mapTestClass.FindEntry(key)->GetValue().GetInt32()));
            	
            	
            	// using BaseArray with instances that can NOT be copied (DISALLOW_COPY_AND_ASSIGN)
            	maxon::BaseArray<TestClassDisallowCopyAndAssign> arrayTestClassDCA;
            	
            	TestClassDisallowCopyAndAssign item1DCA = TestClassDisallowCopyAndAssign(false, 10);
            	TestClassDisallowCopyAndAssign item2DCA = TestClassDisallowCopyAndAssign(true, 20);
            	TestClassDisallowCopyAndAssign item3DCA = TestClassDisallowCopyAndAssign(false, 30);
            	TestClassDisallowCopyAndAssign item4DCA = TestClassDisallowCopyAndAssign(true, 40);
            	
            	arrayTestClassDCA.Append(item1DCA);
            	arrayTestClassDCA.Append(item2DCA);
            	arrayTestClassDCA.Append(item3DCA);
            	arrayTestClassDCA.Append(item4DCA);
            	
            	for (Int32 i = 0; i < arrayTestClassDCA.GetCount(); i++)
            	{
            		GePrint("arrayTestClassDCA[" + String::IntToString(i) + "]: "+String::IntToString(arrayTestClassDCA[i].GetBool())+"/"+String::IntToString(arrayTestClassDCA[i].GetInt32()));
            	}
            	
            	
            	// using HashMap with instances that can NOT be copied (DISALLOW_COPY_AND_ASSIGN)
            	maxon::HashMap<Int32, TestClassDisallowCopyAndAssign*> mapTestClassDCA;
            	mapTestClassDCA.Put(4040, &item1DCA);
            	mapTestClassDCA.Put(1010, &item2DCA);
            	mapTestClassDCA.Put(3030, &item3DCA);
            	mapTestClassDCA.Put(2020, &item4DCA);
            	for (Int32 i = 0; i < mapTestClass.GetCount(); i++)
            	{
            		const Int32 k = mapTestClassDCA.GetNonEmptyBucket(i)->GetKey();
            		TestClassDisallowCopyAndAssign** value = &(mapTestClassDCA.GetNonEmptyBucket(i)->GetValue());
            		GePrint("mapTestClassDCA["+String::IntToString(i)+"]: key["+String::IntToString(k)+"], value["+String::IntToString((*value)->GetBool())+"/"+String::IntToString((*value)->GetInt32())+"]");
            	}
            	
            	key = 2020;
            	GePrint("mapTestClassDCA@Key[" + String::IntToString(key)+"]: "+ String::IntToString(mapTestClassDCA.FindEntry(key)->GetValue()->GetBool()) + "/" + String::IntToString(mapTestClassDCA.FindEntry(key)->GetValue()->GetInt32()));
            	
            	key = 4040;
            	GePrint("mapTestClassDCA@Key[" + String::IntToString(key)+"]: "+ String::IntToString(mapTestClassDCA.FindEntry(key)->GetValue()->GetBool()) + "/" + String::IntToString(mapTestClassDCA.FindEntry(key)->GetValue()->GetInt32()));
            ...
            

            Best, R

            C4DSC 1 Reply Last reply Reply Quote 0
            • C4DSC
              C4DS @r_gigante
              last edited by

              @r_gigante
              Maybe a little late, but thanks for the info anyway. Always useful, and much appreciated!
              I went with a custom implementation using a BaseArray to store the information, and from there used the specific index in the array as the value in an HashMap

              Instead of the wanted:
              maxon::HashMap<Int32, DataStruct> mymap;

              I went with:

              class MyHashMap
              {
              ...
              maxon::BaseArray<DataStruct> mArray;
              maxon::HashMap<Int32, Int32> mArrayIndexMap;
              };
              

              This is more or less what you have described.

              The only drawback here is that I still haven't found out how to implement range-based loop support ... but I went with using the old-fashioned indexed loop usage. Good enough for its purpose.

              1 Reply Last reply Reply Quote 0
              • First post
                Last post