Move assignment warning with virtual inheritance

Can someone tell me how to get rid of the compiler warning for this code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <memory>

class LivingBeing {
		int ID;
	public:
		LivingBeing() = default;
		virtual ~LivingBeing() = default;
		LivingBeing (int id): ID (id) {}
	private:
        virtual LivingBeing& assign (const LivingBeing&) = 0;
};

class CharacterClass: virtual public LivingBeing {
		int level;
	public:
		CharacterClass (int lev): level (lev) {}
};

template <typename DERIVED> class LivingBeingCRTP: virtual public LivingBeing {
  	protected:
        virtual LivingBeing& assign (const LivingBeing& being) override {
			return static_cast<DERIVED&>(*this) = dynamic_cast<const DERIVED&>(being);
		} 
};

class SpellCastingClass: virtual public LivingBeing {
	protected:
		void establishSpellsKnown();
};

class SpellCastingClass1: virtual public SpellCastingClass {};
class SpellCastingClass2: virtual public SpellCastingClass {};

class MultiClass: public CharacterClass, public SpellCastingClass1, public SpellCastingClass2, 
		public LivingBeingCRTP<MultiClass> {
	public:
		MultiClass (int id, int level): LivingBeing (id), CharacterClass (level) {
                  establishSpellsKnown();
           }
};

int main() {}


The compiler warning I'm getting (which I worry will run into problems later when moving objects) is:
C:\DandD>g++ -std=c++11 Test.cpp -Wall -pedantic
Test.cpp: In instantiation of 'LivingBeing& LivingBeingCRTP<DERIVED>::assig
n(const LivingBeing&) [with DERIVED = MultiClass]':
Test.cpp:33:13: required from here
Test.cpp:25:7: warning: defaulted move assignment for 'SpellCastingClass1'
calls a non-trivial move assignment operator for virtual base 'SpellCasting
Class' [-Wvirtual-move-assign]
class SpellCastingClass1: virtual public SpellCastingClass {};
^
Test.cpp:26:7: warning: defaulted move assignment for 'SpellCastingClass2'
calls a non-trivial move assignment operator for virtual base 'SpellCasting
Class' [-Wvirtual-move-assign]
class SpellCastingClass2: virtual public SpellCastingClass {};

I don't know what the problem is really. Currently, SpellCastingClass1 and SpellCastingClass2 need to be virtual derived classes (else I run into ambiguity error with establishSpellsKnown()). I need a solution that does not change them being virtual. Do I have to write a move assignment operator in one of the classes? Removing LivingBeingCRTP<DERIVED>::assign removes the warning, but I need that function though.
Last edited on
That implicit move assignment is deleted under C++11 (virtual bases not allowed in 12.8[class.copy]/23) and defaulted under C++14 (virtual bases allowed). Looks like gcc is generating it as defaulted (perhaps it decided to apply the resolution to the CWG issue 1402), but warning that this does not actually comply with the language standard you requested.

PS: correction, it's actually only warning because it is "dangerous", from gcc docs:

-Wno-virtual-move-assign
Suppress warnings about inheriting from a virtual base with a non-trivial C++11 move assignment operator. This is dangerous because if the virtual base is reachable along more than one path, it will be moved multiple times, which can mean both objects end up in the moved-from state. If the move assignment operator is written to avoid moving from a moved-from object, this warning can be disabled
Last edited on
May be a bug in 4.8.1
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57319

Just out of curiosity, do you really need a hierarchy like that?
Last edited on
@ helios. I've actually simplified my hierarchy a lot to lessen the errors I was getting before. The complexity and multitude of classes in this game requires a complex hierarchy.

@ cubbi. I suspected that a special move assignment operator was needed, but I'm not experienced enough to write move constructors and assignments more complex than the basic ones that use simple std::move and turning pointers to null. Suppressing its second call in LivingBeing? I never wrote code to do something like that before.

First I'll run some tests to see if MultiClass::assign works properly.
Last edited on
built-in move assignment just moves the bases in order, so

built-in MultiClass::operator=(MultiClass&& rhs) calls
CharacterClass::operator=(CharacterClass&& rhs), then
SpellCastingClass1::operator=(SpellCastingClass1&& rhs), then
SpellCastingClass2::operator=(SpellCastingClass2&& rhs), then
LivingBeingCRTP<MultiClass>::operator=(LivingBeingCRTP<MultiClass>&& rhs)
(and then moves every non-static data member)

each of those is a built-in as well, and it calls its own base move assignment operators, which eventually gets to the point of calling

LivingBeing::operator=(LivingBeing&& rhs)
LivingBeing::operator=(LivingBeing&& rhs) <-- note that this is the same rhs, the object on the right.

If LivingBeing::operator= were to take pointers from rhs and replace them with null, on the second call it would take those nulls. That's why the warning. Give your LivingBeing a std::string data member to see what happens to it. Your int is fine, though.

Last edited on
Topic archived. No new replies allowed.