gpt4 book ai didi

c++ - 如何包装抽象类的指针列表?

转载 作者:行者123 更新时间:2023-12-02 10:27:23 25 4
gpt4 key购买 nike

我尝试将指向抽象类(list<shared_ptr<Base>> list_)的智能指针列表包装到某些类(ItemDrawerBox)中。然后在主函数中,我有一个map's的Box,它不起作用。我找到了解决方法,可以使用new,但是我怀疑这只会导致我看不到的错误。如何使其运作?这是代码:

#include <iostream>
#include <list>
#include <map>
#include <memory>
using namespace std;

class Base {
public:
virtual int get() = 0;
};

class Derived : public Base {
public:
Derived(int x) { x_ = x; }
int get() override { return x_; }
private:
int x_;
};

class Item {
public:
Item() {
for (int i = 1; i <= 10; i++) {
list_.push_back(make_shared<Derived>(i));
}
}
list<shared_ptr<Base>>& get_list() { return list_; }
private:
list<shared_ptr<Base>> list_;
};

class Drawer {
public:
Drawer(Item& item) : item_(item) {}
void Draw() {
list<shared_ptr<Base>>& list = item_.get_list();
cout << list.size() << ": ";
while (!list.empty()) {
shared_ptr<Base> pointer = dynamic_pointer_cast<Derived>(list.front());
cout << pointer->get() << " ";
list.pop_front();
}
cout << endl;
}
private:
Item& item_;
};

class Box {
public:
Box() : drawer_(item_) {}
void Draw() { drawer_.Draw(); }
private:
Item item_;
Drawer drawer_;
};

int main() {
Box box;
box.Draw();

map<int, Box> boxes; // it doesn't work, why?
for (int i = 0; i < 3; i++) {
boxes.insert(std::pair<int, Box>(i, Box()));
}
for (auto& b : boxes) { b.second.Draw(); }

map<int, Box*> pointers; // it does work, why?
for (int i = 0; i < 3; i++) {
pointers.insert(std::pair<int, Box*>(i, new Box()));
}
for (auto& b : pointers) { b.second->Draw(); }
for (auto& b : pointers) { delete b.second; }
}
结果如下:
10:  1 2 3 4 5 6 7 8 9 10
0:
0:
0:
10: 1 2 3 4 5 6 7 8 9 10
10: 1 2 3 4 5 6 7 8 9 10
10: 1 2 3 4 5 6 7 8 9 10

最佳答案

在这条线

boxes.insert(std::pair<int, Box>(i, Box()));
您正在成对创建一个临时的 Box对象,该对象已移动到 map 中。
我们称它们为 Box1(创建的临时对象)和 Box2( map 内移动构造的对象)。
创建 Box1时,它正确地具有一个抽屉,该抽屉引用 Box1中的项目。
然后,将其移动到 map 中时,我们会得到 Box2,它的抽屉仍然引用 Box1中的项目。
当我们继续
for (auto& b : boxes) { b.second.Draw(); }
Box1已经被销毁,不再存在。因此,当我们尝试使用对它的引用时,我们使用的是UB的悬空引用。在这种情况下,您得到的结果为0,但同样可以得到崩溃或任何随机输出。
为了解决这个问题,我们可以在 Box中添加一个拷贝构造函数来解决这个问题。
class Box {
public:
Box() : drawer_(item_) {}
Box(const Box& other) : item_(other.item_), drawer_(item_) {}
void Draw() { drawer_.Draw(); }
private:
Item item_;
Drawer drawer_;
};
现在,副本的抽屉将指向正确的项目。
至于带有指针的版本为何起作用,因为我们正在复制指针,所以相同的对象将一直保留直到被删除。没有移动或复制的对象,仅复制了指针,并且复制的指针仍然指向正确的对象。

关于c++ - 如何包装抽象类的指针列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63757483/

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