How to implement a moveable type with MAXON_OPERATOR_MOVE_ASSIGNMENT?
-
Hi,
edit @ferdinand:
How to implement a class that can be stored in a
BaseArray
that has virtual member functions where a class instance is not copyable but moveable?This is specifically about using the macro
MAXON_OPERATOR_MOVE_ASSIGNMENT
.
let's say, I have a class like this, with a virtual function:
class SomeClass { MAXON_DISALLOW_COPY_AND_ASSIGN(SomeClass); public: virtual maxon::Result<void> PopulateArray() { // Fill _vectorArray with something return maxon::OK; } virtual maxon::Result<void> CopyFrom(const SomeClass& src) { return _vectorArray.CopyFrom(src._vectorArray); } private: maxon::BaseArray<maxon::Vector> _vectorArray; public: SomeClass() {} virtual ~SomeClass() {} SomeClass(SomeClass&& src) { // What to do with _vectorArray? } MAXON_OPERATOR_MOVE_ASSIGNMENT(SomeClass); };
Since the class contains a
maxon::BaseArray
, I decorated it with aMAXON_DISALLOW_COPY_AND_ASSIGN()
statement. Therefore, to use it in aBaseArray
, I have to implement aCopyFrom()
function and a move assignment operator. I also added a virtual destructor to avoid compiler error C4265.Let's test it
SomeClass testObject; maxon::BaseArray<SomeClass> testArray; testArray.Append(testObject) iferr_return;
I get the error:
C2338: MAXON_OPERATOR_MOVE_ASSIGNMENT can't be used for classes with virtual functions.
So, long story short: How do I create arrays of classes that don't allow copy and assign, and also can't use
MAXON_OPERATOR_MOVE_ASSIGNMENT
because they have virtual functions? Does that even work at all? And would it work with classes derived fromSomeClass
?Cheers,
Frankedit @fwilleke80:
I guess, the easiest solution is to not store SomeClass objects in a BaseArray, but to store SomeClass* pointers in a PointerArray, right? -
Hello @fwilleke80,
Thank you for reaching out to us. Please remember to consolidate your postings for the initial question of a topic, so that it remains compact. Please also remember to put your question at the beginning of a topic, ideally into the first sentence and not to the end of it. Finally, it is often best to describe what you want to achieve, which has been done here at best implicitly. I have fixed these points here, but please follow them in future threads.
In short, you cannot have classes with virtual member functions that use the macro
MAXON_OPERATOR_MOVE_ASSIGNMENT
as stated in its documentation:This macro can't be used for classes with virtual functions for the sake of safety. Because the created move assignment operator would invoke the constructor, the vtable pointer of the object would be changed if one accidentally used the assignment operator of a base class for an object of a derived class.
This macro must not be used for classes which support concurrent move assignment calls from multiple threads to the same object because the sequence of destructor and move constructor is not thread safe.
You could of course implement the move-operator yourself (you should obey the three/five/zero rule then). But such implementation would then also have exactly that problem the docs talk about. For your case, it could look something like shown in [1]. You could also specialize the relevant operators and constructors for the derived classes, but that could be quite a bit of work, depending on how many there are.
I personally would not bother with all this and simply would not store the objects in the collection. The type maxon::PointerArray you mentioned is one option, although it also takes over the memory management of the "stored" objects for you, so in the end it sort of works like a
BaseArray
.Depending on what you are trying to do, a
WeakRawPtr
or a maxon reference based approach might be better. [2][3]Cheers,
Ferdinand[1]
// The move assignment operator, we just move the internal data which must be moved. But it will not rectify // the general problems described in the docs. // // We should also implement the copy and move constructors. SomeClass& operator =(SomeClass&& src) { _vectorArray = std::move(src._vectorArray); return *this; }
[2] WeakRawPtr Manual: No memory management, but guards against access violations for deleted objects.
maxon::BaseArray<maxon::WeakRawPtr<SomeClass>> _data;
[3] References Manual: Varying degrees of memory management, up to the degree of automated deallocation over ref counting. E.g., a copy-on-write ref, the fanciest type of refs:
maxon::BaseArray<maxon::StrongCOWRef<SomeClass>> _data;
-
Thank you, Ferdinand!
That really does help a lotHave a nice weekend!
-
Hello @fwilleke80 ,
without further questions or postings, we will consider this topic as solved by Friday, the 11th of august 2023 and flag it accordingly.
Thank you for your understanding,
Maxon SDK Group -
@jana sorry, I forgot to flag it myself. All solved, thank you