3

我无法弄清楚.. 看起来我错过了一些简单的东西?我该放MakePointToSameValue什么(1)

  • b.ptr 和 c.ptr 都指向与 a.ptr 相同
  • 换句话说,a.ptr.get() == b.ptr.get() == c.ptr.get()
  • b.ptr 和 c.ptr 最初指向的值被删除

?

struct Test
{
public:
  Test( int val ) :
    ptr( std::make_shared< int >( val ) )
  {
  }

  void MakePointToSameValue( Test& other )
  {
    //what do I put here?
    //other.ptr = this->ptr; //doesn't do it
  }

private:
  std::shared_ptr< int > ptr;
};

Test a( 0 );
Test b( 5 );
Test c( b );

b.MakePointToSameValue( a );

//(1)

复制 ptr 不起作用,因为它不会改变 c(嗯,c.ptr 的引用计数减少了 1)。请注意,我int只是为了简单起见,但它应该适用于不可复制的类型。

为什么?我有一个表示值的类,任何类型的值,用于某种编译器。实际值及其存储方式在实例化时是已知的。唯一知道的是类型。因此,该类存储了一个 shared_ptr ,其中包含稍后确定的值的占位符(对应于编译作为指针或引用传递的函数定义的参数:编译器只知道类型,仅此而已)。在运行时,占位符应替换为实际值。

编辑新的一天,想出了这个。我知道这很简单。

void MakePointToSameValue( Test& other )
{
  other.ptr.swap( ptr );
  ptr.reset();
  ptr = other.ptr;
}

现在的另一个问题是:对于任何符合标准的指针,上述工作是否会按预期工作?

4

2 回答 2

3

这里需要两级间接。虽然您是对的,所有shared_ptr对象都指向一个公共元数据块,其中包含计数和指向实际值的指针,但如果您尝试更新该块以指向不同的对象,您现在将有两个元数据块指向相同的值,每个人对引用计数有自己的不同想法。使用每个元数据块的对象的数量(在它与引用计数相匹配的意义上)是正确的shared_ptr,因此每个块上的计数最终将达到零,但是没有办法知道哪个块是最后一个达到计数的块零(因此应该删除该值)。所以shared_ptr明智地不允许更改元数据中的对象指针。您只能关联shared_ptr使用新的元数据块、新计数、新对象。指向同一对象的其他指针不受影响。

正确的方法是使用第二层间接(shared_ptr<shared_ptr<int> >)。这样一来,每个对象只有一个元数据块和一个计数。您的更新发生在中间 shared_ptr 上。

于 2012-07-04T16:03:11.320 回答
1

好吧,据我了解您的要求,shared_ptr不包含任何此类机制;任何常规类型也不会。如果你想要这种行为,你必须自己编写代码。我的建议:添加一个私有静态std::list<std::weak_ptr<Test>> registryTest通过将每个实例添加到构造函数中的列表来注册每个实例registry,并确保在析构函数中将其删除。

然后使用该注册表MakePointToSameValue来遍历所有实例并重置ptr.

如果您对效率感兴趣并且实例多于三个,则需要将 ; 替换listunordered_set; 也许使用unique_ptr而不是shared_ptr在你的Test课堂上。

回答附加问题:不,它不起作用。查看文档reset():它重置了一个特定的实例shared_ptr:它对任何其他实例都不做任何事情(也不知道)。当控制块中的引用计数达到零时,它还会破坏指针对象,但仅此而已。

于 2012-07-03T12:19:20.080 回答