C++ 如果我碰巧注意到弱ptr,我是否应该调用reset';过期了吗?
我有一组C++ 如果我碰巧注意到弱ptr,我是否应该调用reset';过期了吗?,c++,shared-ptr,weak-ptr,C++,Shared Ptr,Weak Ptr,我有一组生物对象,这些对象是使用std::make_shared和std::shared_ptr在我的应用程序的一部分中创建和拥有的 我还使用std::weak_ptr跟踪World对象中的零个或一个生物的选择 当我发现不再需要它时,这会释放内存。令人烦恼的是,这个版本的GetSelection不能是const 我的问题是: 在这种情况下,哪个版本的GetSelection被视为最佳实践 如果模板化代码中出现类似的情况,答案会改变吗?sizeof(T)是未知的,并且可能是巨大的?或者在C++14
生物
对象,这些对象是使用std::make_shared
和std::shared_ptr
在我的应用程序的一部分中创建和拥有的
我还使用std::weak_ptr
跟踪World
对象中的零个或一个生物的选择
当我发现不再需要它时,这会释放内存。令人烦恼的是,这个版本的GetSelection
不能是const
我的问题是:
在这种情况下,哪个版本的GetSelection
被视为最佳实践
如果模板化代码中出现类似的情况,答案会改变吗?sizeof(T)
是未知的,并且可能是巨大的?或者在C++14中,可能涉及到std::make_shared
如果第二个版本总是最好的,那么std::weak_ptr::expired
和lock
自己不这样做的理由是什么
首先应该注意的是,std::make_shared
的安置策略是可选的,即标准不要求实现执行此优化。这是一个不具约束力的要求,这意味着完全一致的实现可能会选择放弃它
回答您的问题:
考虑到您似乎只有一个选择(并且您没有因此而通过保留许多控制块来增加内存使用),我认为应该保持简单。内存是瓶颈吗?这对我来说是一个巨大的挑战。您应该编写更简单的代码,可以在其中应用const
,然后在需要时返回并进行优化
答案并不是无条件地改变,而是取决于问题领域和瓶颈是什么。如果您正在分配一个“巨大”的对象(比如说100千字节),并且该对象的空间在一个相对未使用的控制块中游荡,直到被替换为止,这可能不是您的瓶颈,也可能不值得编写更多的代码(本质上更容易出错、维护和破译)来“解决”
由于std::weak_ptr::lock
和std::weak_ptr::expired
是const
,根据C++11的const
解释,它们必须是线程安全的。因此,给定一些std::weak_ptr
,同时调用lock()
和expired()
的任意组合必须是安全的。在引擎盖下,std::weak_ptr
存储一个指向控制块的指针,它通过该指针检查/增加/等原子计数器,以确定对象是否已过期,或查看是否可以获取锁。如果要在std::weak_ptr
内部实现优化,则必须以某种方式检查控制块的状态,然后在指针过期时自动删除指向控制块的指针。这将导致每次访问std::weak_ptr
,都会产生开销(即使这可以通过原子实现,也会有开销),所有这些都是为了一个小的优化
对于绝大多数情况,GetSelection
的第一个版本更好。此版本可以是const
,不需要额外的同步代码即可实现线程安全
在无法提前预测确切使用模式的通用库代码中,仍然首选第一个版本。但是,在同步代码已经到位的情况下,保护对弱\u ptr
的访问,插入调用reset
释放内存并在以后更快地使用指针不会有什么坏处。这个非常小的优化本身不值得放入同步代码
鉴于前两个答案,最后一个问题没有实际意义。但是,有两个强有力的理由可以说明,当指针过期时,没有弱\ptr::lock
自动重置指针:
- 有了这种行为,就不可能在
之前实现弱ptr::owner\u,从而使用弱ptr
作为关联容器中的键类型
此外,如果没有额外的同步代码,即使在活动对象上使用弱\u ptr::lock
,也无法实现。这将导致性能损失,远远大于更急切地释放内存所带来的微小收益
替代解决方案:
如果浪费的内存被认为是一个需要解决的实际问题(可能共享对象确实很大,并且/或者目标平台的内存非常有限),另一个选择是使用shared\u ptr(new T)
创建共享对象,而不是make\u shared
。这将更早地释放分配给T的内存(当指向它的最后一个共享\u ptr
被破坏时),而小控制块将单独存在。我将发布我自己的(不完全令人满意)过一会儿再回答,但我真的很想看看其他人怎么说。如果你想GetSelection
保持const
,你可以在第二种情况下使弱ptr
成员可变。您的意思是,在selection.lock()
返回一个空的std::shared_ptr
之后,以前管理的对象不知何故没有释放?@T.C.正确,但我会说“令人恼火的是,此版本要求我的选择成员是可变的”。关键是我根本没有改变弱ptr
对象的可观察状态,我只是在尝试一点优化,可以说这可以在弱ptr
内部完成。这直接关系到
void World::SetSelection(const std::shared_ptr<Creature>& creature) {
selection = creature;
}
std::shared_ptr<Creature> World::GetSelection() const {
return selection.lock();
}
std::shared_ptr<Creature> World::GetSelection() {
const auto ret = selection.lock();
if (!ret)
selection.reset();
return ret;
}