繁体   English   中英

如何改进作为 class 成员变量的智能指针的取消引用

[英]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.

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