J'ai essayé de créer des références de structure struct simples à certaines valeurs de son parent. Parent est stocké dans unique_ptr
, à l'intérieur d'un vecteur. Il est instancié avant d'être déplacé là. Après le mouvement, les références ne sont bien sûr plus valables. J'ai trouvé un moyen de les réintégrer, mais je déteste la solution (c'est montré ci-dessous). Je pensais que le constructeur de mouvement est appelé collection.push_back(std::move(d))
, mais ce n'est pas le cas pour Derived
. Il pourrait être pour unique_ptr
cependant, je ne suis pas sûr de cela. Ma question est - quelle devrait être la façon préférée de faire face à de telles situations? Y a-t-il une meilleure solution que celle que j'ai présentée ci-dessous? Le remplacement d'un constructeur de déplacement de unique_ptr
est-il utile? Est-ce une bonne idée? Ou, est-ce même une bonne idée de concevoir des objets de la manière présentée ci-dessous?Déplacer le constructeur et le vecteur de unique_ptr
#include <iostream>
#include <vector>
#include <memory>
// Inner object of every Base instance, is used to keep reference to
// Base's inner variables
struct Ref {
Ref(double &x, double &y)
: x(x)
, y(y)
{
}
std::reference_wrapper<double> x;
std::reference_wrapper<double> y;
};
struct Point {
double x;
double y;
};
struct Base {
virtual ~Base() { }
// every derived class uses this vector
std::vector<Ref> refs;
// some meaningless pure virtual method, ignore it
virtual void draw() = 0;
};
struct Derived : public Base {
Derived() {
std::cout << "Derived constructed" << std::endl;
}
// Method for adding point and relating it with
// a reference in refs vector
void add(double x, double y) {
points.push_back({x, y});
refs.push_back({points.back().x, points.back().y});
}
// some meaningless pure virtual method, ignore it
virtual void draw() override { }
// this vector is specific to this particular derived class
std::vector<Point> points;
};
int main() {
// some vector for storing objects
std::vector<std::unique_ptr<Base>> collection;
{
auto d = std::unique_ptr<Derived>(new Derived());
d->add(0.01, 0.02);
d->add(1.111, 2.222);
d->add(14.3333, 3.1414);
collection.push_back(std::move(d));
}
// posible solution (I hate it)
{
auto d = std::unique_ptr<Derived>(new Derived());
d->add(0.01, 0.02);
d->add(1.111, 2.222);
d->add(14.3333, 3.1414);
collection.push_back(std::move(d));
auto c = dynamic_cast<Derived *>(collection.back().get());
for (int i = 0; i < c->points.size(); i++) {
c->refs[i].x = c->points[i].x;
c->refs[i].y = c->points[i].y;
}
}
// Let's take 1st vector element and cast it to Derived
{
auto d = dynamic_cast<Derived *>(collection[0].get());
std::cout << "values from points vector:" << std::endl;
// These work correctly after moving
std::cout << d->points[0].x << std::endl;
std::cout << d->points[0].y << std::endl;
std::cout << d->points[1].x << std::endl;
std::cout << d->points[1].y << std::endl;
std::cout << d->points[2].x << std::endl;
std::cout << d->points[2].y << std::endl;
std::cout << "values from refs vector:" << std::endl;
// References of course do not work anymore
std::cout << d->refs[0].x << std::endl;
std::cout << d->refs[0].y << std::endl;
std::cout << d->refs[1].x << std::endl;
std::cout << d->refs[1].y << std::endl;
std::cout << d->refs[2].x << std::endl;
std::cout << d->refs[2].y << std::endl;
}
// Let's take 2nd vector element and cast it to Derived
{
auto d = dynamic_cast<Derived *>(collection[1].get());
std::cout << "values from points vector:" << std::endl;
// These work correctly after moving
std::cout << d->points[0].x << std::endl;
std::cout << d->points[0].y << std::endl;
std::cout << d->points[1].x << std::endl;
std::cout << d->points[1].y << std::endl;
std::cout << d->points[2].x << std::endl;
std::cout << d->points[2].y << std::endl;
std::cout << "values from refs vector with ugly fix:" << std::endl;
// References of course do not work anymore
std::cout << d->refs[0].x << std::endl;
std::cout << d->refs[0].y << std::endl;
std::cout << d->refs[1].x << std::endl;
std::cout << d->refs[1].y << std::endl;
std::cout << d->refs[2].x << std::endl;
std::cout << d->refs[2].y << std::endl;
}
return 0;
}
Sortie:
Derived constructed
Derived constructed
values from points vector:
0.01
0.02
1.111
2.222
14.3333
3.1414
values from refs vector:
0
0.02
4.94602e-317
4.94603e-317
14.3333
3.1414
values from points vector:
0.01
0.02
1.111
2.222
14.3333
3.1414
values from refs vector with ugly fix:
0.01
0.02
1.111
2.222
14.3333
3.1414
Vos références s'invalidés par 'points.push_back ({x, y}); ', pas' collection.push_back (std :: move (d)); '. Ce dernier appelle un constructeur de déplacement de 'unique_ptr', mais c'est toujours le même objet' Derived'. – aschepler
De plus, 'Base' a besoin d'un destructeur virtuel. – aschepler
@aschepler merci! J'ai oublié à ce sujet - ajouté. Wow, vous avez raison 'points.push_back ({x, y});', aucune idée de comment j'ai raté cela, merci! – solusipse