繁体   English   中英

我应该使用const引用还是boost :: shared_ptr?

[英]Should I use a const reference or a boost::shared_ptr?

我创建了一些C ++类,以将纸牌游戏建模为学习练习。

我有SolitaireGame的类,CardStack(棋盘上的十堆纸牌之一)和一张纸牌。 我当前的模型表明SolitaireGame拥有104个Card对象的向量-我称之为“鞋子”。 SolitaireGame还可以跟踪10个CardStack,它们实际上是存储在鞋子中的Card对象地址的双端队列。 Deck and Hand从CardStack继承。 我通过指向存储在鞋子中的原始对象的指针将卡片从Deck传递到Hand到Cascade。

根据我收到的关于问题的许多答案,我不应该通过指针传递Card的周围,而应该使用const引用。 原因是存储在矢量中的对象可以使它们的地址移动,因此将其地址存储在任何地方都是禁止的。 我最近开始研究boost :: sharedptr。 人们对在这里使用shared_ptr到Card有什么想法?

这是类的简化版本:

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;

};

原因是存储在矢量中的对象可以使它们的地址移动,因此将其地址存储在任何地方都是禁止的。

出于相同的原因,存储(常量)引用与存储指针一样糟糕。 如果只要其他对象持有指向其中对象的指针,向量的大小就不会改变,那么您应该是安全的。

使用C ++进行编程时,您应始终确定谁“拥有”一个对象,例如,由谁负责在不再需要该对象时将其删除。 如果没有自然对象所有者,则可以求助于像boost::shared_ptr这样的智能指针,它们使用引用计数或垃圾回收来管理对象的生存期。

在您的情况下,很明显SolitaryGame实例拥有所有卡。 此外,游戏中的卡数是固定的。 因此,您可以轻松地将牌的指针传递给依赖于游戏实例的对象。

删除游戏后,所有卡都将被删除,剩余指针将无效,但是此时,其他持有卡指针的对象也应被删除。

是的,如果您要获取您的元素的地址

vector<Card> _shoe;

并将它们放入您的

deque<Card *> _cards;

正如您所描述的,肯定有问题。 您的向量可能会重新分配,从而使向量的Card元素的地址不再有效。

传递对矢量内容的引用(const或其他方式)将具有与传递指针相同的问题。 在C ++中,引用实际上是一个薄薄的指针。 与指针的唯一区别在于其使用方式(作为别名)不能被“未seseed”,被设置为NULL,以及不能与别名类型区分开(您不能拥有别名)。卡参考的向量)。 引用没有任何特殊的引用计数或您使用其他垃圾收集语言获得的任何内容。 因此,当向量重新分配时,如果有人持有对卡片组中任何卡的引用,则这些引用将像指针一样容易失败。

用boost :: shared_ptr的Cards替换向量可以解决您的问题。 一个boost :: shared_ptr被引用计数。 这意味着它会跟踪基础对象存在多少个引荐来源。 您的向量将是shared_ptrs的向量,而不是对象本身的向量。 因此,当重新分配向量时,您只是在重新分配期间临时将新的引荐来源者添加回基础对象,然后向量将居住在重新分配空间中的shared_ptr替换了shared_ptr。 基础对象不动。

我将更进一步,建议不要给每个人一个shared_ptr。 boost :: weak_ptr传递给非所有者。 boost :: weak_ptr是对基础数据的弱引用。 当需要时,weak_ptr为某人提供了一个获取shared_ptr的句柄。 它不参与基础数据的引用计数。 因此,您可以首先检查基础数据是否被所有者删除。 然后,如果未删除它,则获取一个shared_ptr(参与引荐来源网址计数的临时成员)并执行所需的操作。

您不能将引用存储在容器中,因此,如果要共享访问,则只能使用指针。 shared_ptr似乎毫无意义,因为您不希望管理内存。

但是,如果我制作了Card类,它将仅包含一个或两个整数,并且将是不可变的(除非这些是可以更改其西装和值的魔术卡)。 因此,我只会使用卡的副本。

返回时,您可能更喜欢引用(除非您要存储指向返回值的指针,否则最终看起来会很奇怪)。 但就我个人而言,我只是按价值回报。

我认为上述问题的解决方法是费迪南德(Ferdinand)的解决方法,但我想在这种情况下对boost :: shared_ptr的使用进行评论。

如何 ,你的卡对象? 如果它们足够小(例如几个整数),那么复制卡本身可能会比使用boost :: shared_ptr好,因为复制boost :: shared_ptr并不便宜(由于引用计数上的线程同步)。 这基于不需要具有唯一标识的Card对象,例如,十个黑桃Card对象与其他对象一样好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM