【问题标题】:Why aren't these shared_ptrs pointing to the same container?为什么这些 shared_ptrs 不指向同一个容器?
【发布时间】:2010-04-04 16:40:04
【问题描述】:

我有一个班级模型:

class Model
{
    ...

    boost::shared_ptr<Deck>  _deck;
    boost::shared_ptr<CardStack> _stack[22];
};

Deck 继承自 CardStack

我试图让_stack[0] 指向与_deck 指向相同的东西:

{
    _deck = boost::shared_ptr<Deck>(new Deck());
    _stack[0] = _deck;
}

似乎将_stack[0] 分配给_deck 会导致生成_deck 的副本。 (我知道这一点是因为对 _stack[0] 的修改不会导致对 _deck 的修改。)我怎样才能让它们指向同一个东西?

好的 - 没有调用复制构造函数。我已经通过实现它并查看它是否被调用来验证这一点 - 它没有。

但是 - 我有一个在 CardStack 对象上运行的函数:

void TransferSingleCard(CardStack & src, CardStack & dst, Face f)
{
    if( !src._cards.empty() )
    {
        src._cards.back().SetFace(f);
        dst.PushCard(src._cards.back());
        src._cards.pop_back();
    }   

}

现在 - 当我打电话时:

{
    TransferSingleCard(*_stack[DECK], _someotherplace, FACEDOWN);
    std::cout << *_stack[DECK];
    std::cout << *_deck;
}

我得到这个输出(CardStack 上的 std::cout 将打印出该堆栈的大小):

Num(103) TOP
Num(104) TOP

...所以我得出结论(不正确?)_stack[DECK] 指向不同的东西。

甲板

class Deck : public CardStack
{
public:
    Deck(int numsuits=2, StackIndex index = NO_SUCH_STACK );
    Deck::Deck( const Deck & d);
    int DealsLeft() const;
    void RecalcDealsLeft();
private:
    int _dealsleft;
};

【问题讨论】:

  • 应该可以。您遇到了什么错误,或者您如何知道正在制作副本。
  • @Space_C0wb0y - 我知道它是一个副本,因为我修改了_stack[0](它基本上是Card 对象的容器),方法是从中拉出Card 对象。然后我对它们都进行了查询 - _stack[0] 的大小按预期减小了,但 _deck 的大小仍然与拉取之前的大小相同。
  • 您是否尝试过将两个shared_ptr 设为同一类型?你能展示你做了什么修改吗?另外,尝试实现一个复制构造函数,看看它是否被调用(它不应该)。你能显示DeckCardStack 类吗?
  • 什么是DECK?你确定_stack[DECK]_deck 指的是同一个对象吗?您最初说 _stack[0]_deck 是相同的,但现在您有了一个新变量。
  • @Dennis Zickefoose - 是的。抱歉,为了方便,我使用了 0。代码实际上使用了调用_stack[DECK] = _deck;,其中DECK 在枚举中定义为0。它在Model 构造函数期间执行此分配。我还没有打印出这两个指针的地址,但是我没有看到_stack[DECK]_deck 的任何其他分配。

标签: c++ boost shared-ptr


【解决方案1】:

不清楚您在问什么 - 请考虑以下代码:

#include <iostream>
#include "boost/shared_ptr.hpp"
using namespace std;

struct A {
    virtual ~A() {
        cout << "destroyed" << endl;
    }
};

struct B : public A {
};

int main() {
    boost::shared_ptr<B> b( new B );
    boost::shared_ptr<A> a;
    a = b;
}

只出现一条“销毁”消息,表示没有复制。

【讨论】:

    【解决方案2】:

    这个例子——源自@Neil 的回答,试图模仿你所说的正在发生的事情。您能否检查它在您的系统上是否按预期工作(A 和 B 具有相同的计数)。

    然后我们可以尝试修改此代码或您的代码,直到它们匹配为止。

    #include <boost/shared_ptr.hpp>
    #include <iostream>
    
    class A {
        public:
        virtual ~A()
        {
            std::cerr << "Delete A" << std::endl;
        }
        int _count;
        void decrement()
        {
            _count --;
        }
    };
    class B : public A {
        public:
        virtual ~B()
        {
            std::cerr << "Delete B" << std::endl;
        }
    };
    
    int main()
    {
        boost::shared_ptr<B> b(new B);
        b->_count = 104;
        boost::shared_ptr<A> a;
        a = b;
    
        a->decrement();
    
        std::cerr << "A:" << a->_count << std::endl;
        std::cerr << "B:" << b->_count << std::endl;
        return 0;
    }
    

    编辑:

    所以从注释中,我们知道原来的指针是正确的,所以现在我们需要追踪。

    要么:

    1. 记录指针以查看它们何时更改。
    2. 在调试器中使用观察点来查看指针何时发生变化。
    3. 使用第三个共享指针查看更改的指针。
    4. 引入一个同时改变两个指针的函数。

    【讨论】:

    • 好吧,我回到了基础,您的代码证明它们确实开始指向同一件事。 TransferSingleCard() 甚至可以工作 - 大小相同。然而,更进一步,TransferSingleCard() 为每个指针提供了不同的结果。
    • 我猜这意味着其中一个指针正在发生变化 - 我建议每次打印出大小时记录指针地址,并查看它们何时发生变化。
    • 是的,你是对的。 _deck 指针正在通过 boost::shared_ptr::reset() 重置为其他值。我想我曾假设reset() 不会更改_deck 的地址(不知道为什么回想起来),并且_stack[DECK] 也不必更改。无论如何 - 谢谢。
    【解决方案3】:

    认为问题是你在这里分配不同的类型。 boost::shared_ptr 是一个模板,模板不是多态的,即使它们中的类型是多态的。所以发生的事情是,您的编译器看到了从 boost::shared_ptr&lt;Deck&gt;boost::shared_ptr&lt;CardStack&gt; 的赋值,并注意到它可以通过调用 CardStack 的复制构造函数来复制 Deck 对象来进行赋值。

    我认为您希望作业看起来像这样:

    _stack[0] = boost::static_pointer_cast<CardStack>(_deck);
    

    这将按照您期望的方式进行转换。

    【讨论】:

    • @BeeBand - 我刚刚注意到您更新了问题,并且您已经验证它没有调用复制构造函数。在这种情况下,上述技术将无济于事。
    【解决方案4】:

    我想你可能想要 shared_array 换成 _stack 。 . .查看来自 boost.org 的 shared_ptr 上的文档,具体来说:

    http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm

    "通常,shared_ptr 不能 正确持有指向 a 的指针 动态分配的数组。看 shared_array 用于该用途。”

    另外,请注意 T* get() 函数(无正当理由请勿使用),它返回托管指针(在本例中为 shared_ptr)持有的原始指针。

    【讨论】:

    • CardStack 基本上是std::deque&lt;Card&gt; 的包装。 shared_array 还适用吗?
    • 如果你的代码中有一个指向数组的 shared_ptr 就可以了。我可能误会了。 . .
    猜你喜欢
    • 2021-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-09
    • 1970-01-01
    • 2020-06-17
    • 1970-01-01
    • 2015-02-12
    相关资源
    最近更新 更多