[英]How to improve dereferencing of smart pointer that is a member variable of class
我有以下 class 结构 -
typedef std::shared_ptr<Inner> InnerPtr;
class Outer {
private:
const InnerPtr ptr_;
public:
Outer(const InnerPtr& ptr) : ptr_(ptr) {}
int calculate(int id) {
return ptr_->calculate_other(id);
}
}
在这里, Outer::calculate()
可能会被调用很多次(以百万计)。
由于每次调用Outer::calculate()
都会取消引用ptr_
,我认为与仅使用 object 相比,它会对性能产生影响。
所以我想出了这个 -
typedef std::shared_ptr<Inner> InnerPtr;
class Outer {
private:
Inner& obj_; // to reference *ptr_
const InnerPtr ptr_; // still need to hold a copy of smart pointer to ensure obj stays in memory during the lifetime of Outer
public:
Outer(const InnerPtr& ptr) : ptr_(ptr), obj_(*ptr) {}
int calculate(int id) {
return obj.calculate_other(id);
}
}
我不确定这是否是最佳解决方案。 我正在寻找改进calculate
function 的建议。
注意:假设传递给Outer()
的ptr
是一个非空共享指针
引用通常在 C++ 中作为硬件级别的指针实现,当它不能完全删除时(因为逻辑上它是一个别名)。 从 class 的正文中删除引用非常困难; 我不知道有尝试的编译器(除了在某些情况下可能完全消除 class 实例之外)。
就生成的程序集而言,遵循Inner const&
和shared_ptr<Inner const>const
之间的区别基本上是没有的。
现在,您误解了const
的工作原理; const InnerPtr
是指向非 const 值的 const 指针,而const Inner&
是对 const 值的引用。 但我希望这不是故意的。
现在, Foo&
类似于Foo* const
,因此顶级const
可以以某种方式导致一些优化; 您不得更改任何一点。 这可能导致编译器能够证明Foo&
在两位代码中引用相同的 object 而无法证明Foo*
确实如此。
但是,在您的示例中,您有一个const shared_ptr
,它也有顶级const
。
一般来说,过早的优化是万恶之源。 但是过早的悲观化(与优化相反)也是如此。 遵循智能指针不是过早的压力化,您的参考优化是过早优化的一个例子。 只有当您已经确定那里存在性能瓶颈时,您才应该考虑进行此类更改。
老实说,当您从右值共享 ptr 构建Outer
class 时,您更有可能遇到由构造函数中无关的引用计数增加引起的问题,而不是您发现的问题。 更重要的是,额外的原子引用计数将是一个扩散的减速,因为原子操作同步不会在代码运行时导致大部分减速,而是在破坏 CPU 缓存并使程序成为 rest慢点。
所以改变这个:
explicit Outer(InnerPtr ptr) : ptr_(std::move(ptr)) {}
消除悲观情绪; 现在:
Outer outer( GenerateInnerPtr() );
引用计数的增加和减少比以前少 1 个,并且没有其他情况导致更多的引用计数增加/减少。
第一的:
过早的优化是编程中万恶之源(或至少是万恶之源)
是一个重要的引用,因为大多数时候,人们有错误的理解是什么让程序变慢,什么变快。
第二:假设间接使您的程序变慢。 那么最大的问题是:你需要间接吗? 您的问题对此缺乏明确的答案。 生命周期管理或 object 多态性是原因吗? 我强烈认为,如果您可以进行这些优化,您就可以完全消除间接寻址。
第三:我认为更重要的是编译器是否能够内联所有计算 function 调用。 因此,您对内部 class 的定义看起来如何也很重要。 这就是总是发布一个最小的完整示例的原因之一
第四:如果你仍然非常关心你的程序的性能配置文件,也可以使用https://godbolt.org/ 。
更新,第五:我忘了提:算法复杂性通常是性能差的更大问题,意思是:你循环了几次? 你的循环是嵌套的吗? 你能在创建之前或创建时计算吗? 你能缓存值吗?
我不确定这是否是最佳解决方案。
可能不会。 只要您使用优化器,通过引用间接与通过共享指针间接一样昂贵,因此您不一定要节省任何东西,而您通过使 class 不可分配来支付费用,并且只是更大存储地址两次。
缓存对Inner
object 的引用没有任何改进,因为在所有现有实现中,引用都是作为指针实现的。 基本上,您只是复制了已经属于shared_ptr
的指针并增加了Outer
object 的大小。
除非您能够将Inner
作为Outer
的成员直接缓存,或者至少缓存其数据的某些重要子集,否则您几乎无能为力。 你得重新考虑一下Inner
类和Outer
类的设计,是否可以合并。
另一点要考虑的是,是否可以优化代码的 memory 访问模式。 例如,如果有一个Outer
对象列表,您可以对其调用calculate
,如果每个Inner
object 是单独分配的,则对Inner
对象的访问可能是不可预测的。 如果这些对象在连续缓冲区中线性分配(例如,通过使用自定义 memory 分配器在vector
中),您可能会提高性能。
当然,正如其他人所建议的那样,您应该分析您的代码,看看这段代码是否真的是一个瓶颈,以及任何更改是否确实提高了性能。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.