我的问题最好用代码示例来说明,所以让我们开始吧:
class Game
{
// All this vector does is establish ownership over the Card objects
// It is initialized with data when Game is created and then is never
// changed.
vector<shared_ptr<Card> > m_cards;
// And then we have a bunch of pointers to the Cards.
// All these pointers point to Cards from m_cards.
// These could have been weak_ptrs, but at the moment, they aren't
vector<Card*> m_ptrs;
// Note: In my application, m_ptrs isn't there, instead there are
// pointers all over the place (in objects that are stored in member
// variables of Game.
// Also, in my application, each Card in m_cards will have a pointer
// in m_ptrs (or as I said, really just somewhere), while sometimes
// there is more than one pointer to a Card.
}
现在我想做的是制作这个Game类的深层副本。我创建了一个带有新shared_ptrs的新向量,它指向新的Card对象,它们是原始Card对象的副本。那部分很容易。
然后麻烦开始了,应该更新m_ptrs的指针以指向m_cards中的卡片,这不是一项简单的任务。
我能想到的唯一方法是在复制m_cards(使用map[oldPtr] = newPtr
)期间创建一个地图并填充它,然后使用它来更新m_ptrs。但是,这只是O(m * log(n))
(m = m_ptrs.size(); n = m_cards.size()
)。因为这将是一个非常常规的操作*我想有效地做到这一点,我觉得应该可以在O(m)
使用自定义指针。但是,我似乎无法找到一种有效的方法。有人吗?
*它用于为AI创建测试平台,让它“尝试”不同的动作
编辑:我想补充一下接受答案,因为我还没有。我等到我回到这个项目之后(因为我在这个项目上做了太多工作,所以我走上了一条小道 - 如果你这么做是为了保持乐趣),所以可能需要一段时间才能接受一个答案。不过,我会在一段时间内接受答案,所以不要担心:P
编辑nr 2:我还没有回到这个项目。现在,我正在考虑采用O(m * log(n))
方式而不是抱怨,然后看看它是否需要更快。但是,由于我最近花了一些时间来学习我的模式,我也认为我真的需要在某个时候重构这个项目。哦,我可能只是花了一些时间来处理这个问题,并掌握了我所掌握的所有新知识。因为没有一个答案说“只是坚持使用hashmap,稍后再看它是否真的需要更快”(如果有的话我真的很失望,因为它不是我的问题的答案),我是推迟回答答案,直到我回到这个项目。
编辑nr 3:我仍然没有回到这个项目。更准确地说,它已被无限期搁置。我很确定我现在不会过度弯腰O(m * log(n))
,然后如果事后证明这是个问题,那么可能会稍后看看。然而,这对我的问题来说不是一个好的答案,因为我明确要求提高性能。我不想再接受答案了,我选择了最有帮助的答案并接受了答案。
答案 0 :(得分:3)
将指针存储为索引。 正如你所说,他们都指向m_Cards,这是一个可以被索引的向量(这是正确的英语?)。 要么这样做只是为了存储,并在加载时将它们转换回指针。 或者您可能会考虑使用索引而不是指针。
答案 1 :(得分:0)
如何保持卡元素索引而不是指针:
vector<int> m_indexes; ... Card* ptr = &m_cards[m_indexes[0]];
可以无需更改即可复制带索引的矢量。
答案 2 :(得分:0)
我最近遇到了一个非常类似的问题:克隆由指针和std :: vector实现的类内部结构作为对象存储。
首先(尽管与问题无关),我建议要么使用智能指针,要么使用普通结构。就您而言,这意味着使用vector<weak_ptr<Card> > m_ptrs
代替原始指针更为有意义。
关于问题本身-另一个可能的解决方法是在复制构造函数中使用指针差异。我将针对对象向量进行演示,但是使用共享指针将使用相同的原理,唯一的区别在于m_cards的复制(如果要复制对象,则不应该简单地使用赋值,而应复制m_cards
元素-逐个元素)。
非常重要,该方法仅适用于保证因此存储了元素(矢量,数组)的容器。
另一个非常重要的时刻是,m_ptrs
元素应仅表示内部 Card
结构,即。 e。它们必须仅指向内部m_cards
元素。
// assume we store objects directly, not in shared pointers
// the only difference for shared pointers will be in
// m_cards assignment
// and using m_cards[...].get() instead of &m_cards[...]
vector<Card> m_cards;
vector<Card*> m_ptrs;
在这种情况下,可以使用采用线性时间的指针算法轻松地计算出指针数组。在这种情况下,您的副本构造函数将如下所示:
Game::Game(const Game &rhs) {
if (rhs.m_cards.empty())
return;
m_cards = rhs.m_cards;
// if we have vector of shared pointers
// and we need vector of pointers to objects clones
// something like this should be done
// for (auto p: rhs.m_cards) {
// // we must be certain here that dereferencing is safe,
// // i. e. object must exist. If not, additional check is required.
// // copy constructor will be called here:
// m_cards.push_back(std::make_shared<Card>(*p));
// }
Card *first = &rhs.m_cards[0];
for (auto p: rhs.m_ptrs) {
m_ptrs.push_back(&m_cards[p - first]);
}
}
基本上,在此Deepcopy方法中,您仍将使用索引,但是保留了在其他类方法中使用指针的便利,而无需单独存储索引。
无论如何,要使用这种结构,您应该确切地知道您对类成员的处理方式以及原因,这需要更多的手动控制(例如,至少要在m_cards
中添加/删除元素。应该有意识地完成,否则m_ptrs
甚至在不复制对象的情况下也很容易损坏。