gpt4 book ai didi

c++ - move unique_ptr 的构造函数和 vector

转载 作者:搜寻专家 更新时间:2023-10-31 00:54:57 26 4
gpt4 key购买 nike

我尝试创建简单的结构体来保存对其父类某些值的引用。 Parent 存储在 unique_ptr 中,在 vector 中。它在被 move 到那里之前被实例化。 move 之后,引用当然不再有效。我找到了一种重新实例化它们的方法,但我讨厌这个解决方案(如下所示)。我认为 move 构造函数是在 collection.push_back(std::move(d)) 上调用的,但 Derived 并非如此。虽然它可能是用于 unique_ptr 的,但我不确定。我的问题是 - 处理这种情况的首选方式应该是什么?有没有比我在下面介绍的更好的解决方案?覆盖 unique_ptr 的 move 构造函数会有帮助吗?这是一个好主意吗?或者,以下面介绍的方式设计对象甚至是个好主意吗?

#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;
}

输出:

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

最佳答案

根据标准,引用不应因 move 而失效。真正的问题是 std::vector::push_back 如果容量发生变化,它会验证所有内容。

一个解决方案是使用 std::deque因为它永远不会使 push_back() 的引用无效:

#include <iostream>
#include <vector>
#include <deque>
#include <memory>

struct Point {
double x;
double y;
};

struct Base {
// every derived class uses this vector
std::vector<Point*> refs;

// some meaningless pure virtual method, ignore it
virtual ~Base() = default;
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());
}

// some meaningless pure virtual method, ignore it
void draw() override { }

// this vector is specific to this particular derived class
std::deque<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));

// No ugly fix needed
}

// 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 still work
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;
}

输出:

Derived constructed
values from points vector:
0.01
0.02
1.111
2.222
14.3333
3.1414
values from refs vector:
0.01
0.02
1.111
2.222
14.3333
3.1414

关于c++ - move unique_ptr 的构造函数和 vector ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43646747/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com