简体   繁体   English

如何使shared_ptr的所有副本等于另一个shared_ptr?

[英]How to make all copies of a shared_ptr equal to another shared_ptr?

I cannot figure this out.. Looks like I'm missing something simple? 我无法弄清楚。.好像我缺少一些简单的东西吗? What do I put in MakePointToSameValue so that at point (1) 我在MakePointToSameValue放什么,以便在点(1)

  • both b.ptr and c.ptr point to the same as a.ptr b.ptr和c.ptr都指向与a.ptr相同
  • in other words, a.ptr.get() == b.ptr.get() == c.ptr.get() 换句话说, a.ptr.get() == b.ptr.get() == c.ptr.get()
  • the value originally pointed to by b.ptr and c.ptr gets deleted 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)

Copying the ptr does not work, since it does not alter c (well, c.ptr has it's refcount decreased by one). 复制ptr不起作用,因为它不会更改c(好吧,c.ptr的引用计数减少了一个)。 Note that I use int just for simplicty, but it should work for noncopyable types. 请注意,我只是为了简单起见使用int ,但它应适用于不可复制的类型。

Why? 为什么? I have a class representing values, any type of values, for use in a sort of compiler. 我有一个表示值(任何类型的值)的类,用于某种编译器。 The actual value, nor how it is stored, is known when it gets instantiated. 当实例化实例时,将知道实际值,以及如何存储它。 The only thing known is the type. 唯一已知的是类型。 So the class stores a shared_ptr containing a placeholder for a value determined later on (corresponds to compiling the arguments of a function definition when passed as a pointer or reference: the compiler only knows type, nothing more). 因此,该类存储了一个shared_ptr,其中包含一个占位符,该占位符用于稍后确定的值(相当于作为指针或引用传递时编译函数定义的参数:编译器仅知道类型,仅此而已)。 At runtime the placeholder should be replaced by an actual value. 在运行时,占位符应替换为实际值。

Edit fresh start of the day, came up with this. 编辑一天的新起点,想到了这一点。 I knew it was simple. 我知道这很简单。

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

Additional question now is: will the above work as expected for any standard compliant pointer? 现在的另一个问题是:对于任何符合标准的指针,上述方法都能按预期工作吗?

You need two levels of indirection here. 您在这里需要两个间接级别。 While you're right that all shared_ptr objects point to a common metadata block that contains the count and the pointer to the actual value, if you tried to update that block to point to a different object, you'd now have two metadata blocks pointing to the same value, each with their own different idea of what the reference count is. 没错,所有shared_ptr对象都指向一个包含计数和指向实际值的指针的公共元数据块,但是,如果您尝试更新该块以指向另一个对象,则现在将有两个元数据块指向值相同,每个人对参考计数有不同的看法。 There's the right number (in the sense that it matches the reference count) of shared_ptr objects using each metadata block, so the count on each block will eventually reach zero, but there's no way to know which block is the last block to reach a count of zero (and hence should delete the value). 每个元数据块都有正确的shared_ptr对象数(从某种意义上说,它与引用计数匹配),因此每个块的计数最终将达到零,但是无法知道哪个块是达到计数的最后一块为零(因此应删除该值)。 So shared_ptr sensibly doesn't allow changing the object pointer inside the metadata. 因此, shared_ptr明智地不允许更改元数据中的对象指针。 You can only associate the shared_ptr with a new metadata block, new count, new object. 您只能将shared_ptr与新的元数据块,新计数,新对象相关联。 And other pointers to the same object aren't affected. 并且指向同一对象的其他指针不受影响。

The right way to do this is to use a second layer of indirection ( shared_ptr<shared_ptr<int> > ). 正确的方法是使用间接的第二层( shared_ptr<shared_ptr<int> > )。 That way there's exactly one metadata block and exactly one count for each object. 这样,就只有一个元数据块,并且每个对象只有一个计数。 Your update takes place to the intermediate shared_ptr. 您的更新发生在中间的shared_ptr上。

Well, as far as I understand your requirements, shared_ptr does not contain any such mechanism; 好吧,据我了解您的要求, shared_ptr不包含任何此类机制。 nor would any regular type. 任何常规类型也不会。 If you want this behaviour, you'll have to code it yourself. 如果您想要这种行为,则必须自己编写代码。 My suggestion: add a private static std::list<std::weak_ptr<Test>> registry ; 我的建议:添加一个私有的静态std::list<std::weak_ptr<Test>> registry register each Test instance by adding it to the registry list in the constructor, and make sure to remove it in the destructor. 通过将每个Test实例添加到构造函数中的registry列表中来registry它,并确保在析构函数中将其删除。

Then use that registry in MakePointToSameValue to iterate through all instances and reset the value of ptr . 然后在MakePointToSameValue使用该注册表来遍历所有实例并重置ptr的值。

If you're interested in efficiency and have a bit more instances than three, you'll want to replace the list with an unordered_set ; 如果您对效率感兴趣,并且实例数多于三个,则可以将list替换为unordered_set and perhaps use unique_ptr rather than shared_ptr in your Test class. 并可能在您的Test类中使用unique_ptr而不是shared_ptr

Answer to additional question: no, it won't work. 回答其他问题:不,它不起作用。 Look at the documentation of reset() : it resets one particular instance shared_ptr : it does nothing with (and knows nothing of) any other instances. 查看reset()的文档:它重置一个特定的实例shared_ptr :它对任何其他实例不执行任何操作(也不知道)。 When the reference count in the control block reaches zero, it additionally destroys the pointee, but that's it. 当控制块中的引用计数达到零时,它还会销毁指针对象,仅此而已。

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

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