2009-11-11 65 views
0

我已经创建了一些C++类来模拟纸牌游戏作为学习练习。我应该使用const引用还是boost :: shared_ptr?

我有SolitaireGame,CardStack(板上10堆卡中的一个)和一张卡片的课程。我目前的模型指出,SolitaireGame拥有104个卡片对象 - 我称之为“鞋子”。 SolitaireGame还记录了10个CardStacks,它们基本上是存储在鞋中的Card对象地址的deque。甲板和手从CardStack继承。我通过指向储存在鞋中的原始物体的指针将卡片从卡座传递到级联。

根据我收到的this问题的回答数量,我不应该通过指针传递卡片,而应该使用const引用。原因在于存储在向量中的对象可能会移动它们的地址,因此将它们的地址存储在任何地方都是不允许的。我最近开始寻找boost :: sharedptr。人们怎么看待在这里使用shared_ptr卡片?

下面是类的简化版本:

class SolitaireGame 
{ 
    public: 
    SolitaireGame::SolitaireGame(int numsuits);  

    private:   
     vector<Card> _shoe; 
     Deck _deck; 
     Hand _hand; 
     CardStack _cols[NUM_COLUMNS]; 
     int _numsuits; 
     GameState gamestate; 
}; 

class CardStack 
{ 
    public: 
     CardStack(){ cout << "CardStack constructor" << endl; } 
     CardStack(const CardStack&); 
     CardStack(const deque<Card *> &d); 
     ~CardStack(){ } 

     virtual Card * PullCard(Face f); 
     virtual void PushCard(Card * c); 

     Card * CardAt(int i) const; 
     Card * Top() const; 

     deque<Card *>::iterator Begin() { return _cards.begin(); } 
     deque<Card *>::iterator End() { return _cards.end(); } 

     int Size() const; 
     CardStack& operator=(const CardStack& rhs); 

     friend std::ostream& operator<<(std::ostream &os, const CardStack &obj); 

private: 
     deque<Card *> _cards; 

};

回答

5

的对象存储在矢量可以有自己的地址上搬运,从而存储它们的地址的任何地方的原因存在是一个没有没有。

由于相同的原因,存储(const)引用与存储指针一样糟糕。如果只要其他对象持有指向其中对象的指针,矢量的大小就不会改变,那么您应该是安全的。当用C++编程时,你应该总是决定谁拥有一个对象,例如,谁负责在不再需要时删除它。如果没有自然对象所有者,则可以使用智能指针,如boost::shared_ptr,它们使用引用计数或垃圾回收来管理对象的生命周期。

就你而言,很明显SolitaryGame实例拥有所有卡。而且,游戏中的牌数是固定的。因此,您可以轻松地将卡片的指针传递给依赖于游戏实例的对象。

一旦游戏被删除,所有的卡片将被删除,其余的指针将无效,但此时,其他持卡指针的对象也应该被删除。

+0

感谢您的答复Ferdindand。是的,这是我设想它的工作原理,一个游戏被删除,卡被删除,但它确定,因为所有的Cascades也被删除。我认为我的代码是相当安全的,因为卡片不是动态分配的,并且鞋子总是包含104张不变的卡片。 – BeeBand 2009-11-11 14:40:23

+2

我完全同意这个(+1)。我会补充的唯一的事情是,我将卡片作为(const)引用传递(然后将它们作为指针存储在CardStack中)。我的政策是函数参数和返回值是指针当且仅当NULL是一个有效值,否则使用引用。这可以避免在使用卡之前检查/断言卡的有效性,并使程序员清楚NULL是否无效。 – 2009-11-11 14:44:23

0

您不能将引用存储在容器中,因此如果您想共享访问权限,则只能使用指针。 shared_ptr似乎有些没有意义,因为你不想管理内存。但是,如果我制作了一个Card类,它将只包含一个或两个整数,并且它将是不可变的(除非这些是可以改变其花色和值的魔术卡)。所以我只能使用卡片副本。当你返回时,你可能更喜欢一个引用(除非你想存储指向返回值的指针,最终会看起来很奇怪)。但是,个人而言,我只是为了回报。

2

是如果你正在服用的你

vector<Card> _shoe; 

元素的地址,并将其放置到您的

deque<Card *> _cards; 

绝对有可能是一个问题,像你描述。您的矢量可能会重新分配,导致矢量卡元素的地址不再有效。

传递引用(const或其他)到你的向量的内容将有与传递指针相同的问题。在C++中,引用实际上是一个很薄的指针。与指针的唯一区别是它如何被使用(作为别名)它不能被“取消”的事实,它被设置为NULL,以及它与别名类型无法区分的事实(你不能有卡参考向量)。引用没有任何特殊的引用计数或任何其他垃圾收集语言。所以当你的vector重新分配时,如果有人持有对甲板上任何一张牌的引用,这些引用就会像指针一样容易失败。

用卡的boost :: shared_ptr向量替换你的矢量可以解决你的问题。 boost :: shared_ptr是引用计数。这意味着它会跟踪底层对象有多少引用。而你的向量将是shared_ptrs的向量,而不是对象本身。因此,当重新分配矢量时,只需在重新分配期间临时添加新的引用链回到基础对象,然后该矢量将使用位于重新分配空间的shared_ptr替换shared_ptr。底层对象不会移动。

我会更进一步,建议不要给每个人一个shared_ptr。通过boost::weak_ptr's给非业主。 boost :: weak_ptr是对基础数据的弱引用。 weak_ptr在需要时给予某人一个获得shared_ptr的句柄。它不参与底层数据的引用计数。因此,您可以首先检查基础数据是否已被所有者删除。然后,如果它未被删除,请获取一个shared_ptr(临时参与引用计数)并执行所需的操作。

+0

感谢Doug的回复。所以,如果我正确地理解了你,你认为作为一个额外的预防措施(即使鞋子非常稳定)可以创建鞋作为shared_ptrs向量来动态分配卡?任何想访问这些卡片的人都应该通过弱指针来实现。我喜欢这个想法,我认为这对我来说是一个很好的学习练习。 – BeeBand 2009-11-11 14:43:49

0

我认为费迪南德的答案是上面的路要走,但我想在这个例子中评论boost :: shared_ptr的使用。

如何沉重是你的卡对象?如果它们足够小(几个int就可以了),那么复制这些卡本身可能比使用boost :: shared_ptr更好,因为复制boost :: shared_ptr's并不便宜(由于引用计数上的线程同步)。这取决于你的卡对象不需要具有唯一的身份,例如尽管如此,黑桃Card对象中的十个仍然和其他任何一样好。

+0

你能说一个'独特的身份'吗?是的,每张卡片都是一个独特的物体,尽管可能有4个独立的黑桃卡片对象 - 但这10个黑桃物体中没有一个需要了解其他卡片对象。3卡片对象不重 - 它们可以保存3个整数值。 – BeeBand 2009-11-11 19:23:23

相关问题