I want to re-allocate a class that has self-reference, named CarJoker.
"Re-allocate" here means = to change the address of an object.
This technique is necessary for making every instance of CarJoker lives in a resizable contiguous array e.g. pool.
I think about using std::move, but it can't move CarJoker::wheels in a way that I wish.
(MCVE)
#include <vector>
#include <iostream>
#include <string>
struct Wheel{
void setBlade(){}
void setTwinkle(){}
};
struct CarJoker{
Wheel wa;
Wheel wb;
Wheel wc;
std::vector<Wheel*> wheels;
float hp=5;
CarJoker(){
wheels.push_back(&wa);
wheels.push_back(&wb);
wheels.push_back(&wc);
}
void wow(){
//v want to apply something to every "wheel"
for(auto wheel:wheels){
wheel->setBlade();
}
//v want to apply something to some certain "wheel"
wa.setTwinkle();
}
};
int main(){
CarJoker car1;
CarJoker car2=std::move(car1);
std::cout<<"want to 1 : "<<(car2.wheels[0]== &car2.wa)<<std::endl;
}
With std::move, car2.wheels[0] points to &car1.wa not &car2.wa as I wish.
I know the reason, but that is not my goal, and I don't know an elegant way to fix it.
My poor workaround
Here is an inelegant way (MCVE):-
struct CarJoker{
Wheel wa;
Wheel wb;
Wheel wc;
std::vector<Wheel*> wheels;
float hp=5;
CarJoker(){
reIni(); //: CHANGE (call a new function)
}
void reIni(){ //: CHANGE (create a new function)
wheels.clear();
wheels.push_back(&wa);
wheels.push_back(&wb);
wheels.push_back(&wc);
}
void wow(){
//v want to apply something to every "wheel"
for(auto wheel:wheels){
wheel->setBlade();
}
//v want to apply something to some certain "wheel"
wa.setTwinkle();
}
};
int main(){
CarJoker car1;
CarJoker car2=std::move(car1);
car2.reIni(); //: CHANGE (call a new function)
std::cout<<"want to 1 : "<<(car2.wheels[0]== &car2.wa)<<std::endl;
}
Disadvantage:-
1. It is dirty.
2. I have to create a special-name function (reIni()) for every class that has such symptom that live in the pool. My pool has to recognize that function too (e.g. register using template or virtual function).
My poor workaround 2
struct CarJoker{
Wheel wa;
Wheel wb;
Wheel wc;
std::vector<Wheel*> getWheels(){ //use this instead of "wheels"
std::vector<Wheel*> re;
re.push_back(&wa);
re.push_back(&wb);
re.push_back(&wc);
return re;
}
....
}
I would work, but I feel that it is crazy to workaround like this.
The restriction increases pitfall for coders.
If wheels happen to need to cache computation-expensive result, now it would be expensive to call getWheels() often.
You don't need the
reIni()method. What you need is to add:a copy constructor and a move constructor which both initialize the
wheelsmember the same way as the default constructor does.a copy assignment operator and a move assignment operator which do not copy/move the
wheelsmember.Try this:
That being said, you really shouldn't be using self-referencing fields to begin with. A single
std::array<Wheel, 3>field makes more sense than 3Wheelfields and astd::vector<Wheel*>field, avoiding this whole problem.