HashMap operator = cannot access private member
-
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 thatMAXON_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 tomaxon::HashMap::Insert
replacing the formermaxon::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 usingmaxon::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 themaxon::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?
-
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
(ormaxon::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.
-
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'
-
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
- maxon::BaseArray can store instance derived by classes that are not necessarily defined using
-
@r_gigante
Maybe a little late, but thanks for the info anyway. Always useful, and much appreciated!
I went with a custom implementation using aBaseArray
to store the information, and from there used the specific index in the array as the value in anHashMap
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.