【问题标题】:reference to std::shared:ptr to avoid reference counting引用 std::shared:ptr 以避免引用计数
【发布时间】:2020-05-02 02:29:07
【问题描述】:

我经常面临这样的论点,即通过接受const std::shared_ptr<T>& 可以避免引用计数增加:

void foo(std::shared_ptr<const int> p); 
void foo2(const std::shared_ptr<const int>& p); 

int main(){
   std::shared_ptr<const int> a = std::make_shared<int>(3);

   foo(a);  // calling this function always does reference counting (atomic locks...)
   foo2(a); // calling this function elides reference counting

   std::shared_ptr<int> b = std::make_shared<int>(3);;
   foo2(b); // what happens here? since there is a cast involved creating a temporary ... (NRVO??)
}

但我假设在调用foo2(b) 时不会省略引用计数?但是,编译器或标准实现是否可以以某种方式忽略引用计数。如果调用 foo2(std::move(b)) 会不会更好,以实现这种省略?

【问题讨论】:

  • 如果函数没有将智能指针存储在别处供以后使用,它应该采用普通引用或指针,而不是智能指针。
  • 为了说明@MaximEgorushkin 的观点,请考虑:void foo3(const int * p); void foo4(const int * const &amp; p);
  • 没错,但这不是问题。
  • 原子指令不是,这正是它们的重点。 (这并不是说你试图避免它们是错误的。)

标签: c++ c++11 c++17 shared-ptr c++20


【解决方案1】:

是的,在进入foo2 之前,引用计数必然会增加,退出时会减少。这是因为参数const std::shared_ptr&lt;const int&gt;&amp; p 必须引用std::shared_ptr&lt;const int&gt; 类型的不同对象,因此必须构造和销毁临时对象。

在语言中不可能忽略这个引用计数,因为如果在执行foo2 期间修改了参数b,则参数p 必须保持不受影响;它必须继续指向堆上相同的int 对象,该对象可以被修改但不能被删除。 (这不适用于 a 调用 foo2 时,因为在这种情况下,p 直接引用 a,而不是临时引用,因此通过 p 可以看到对 a 的修改。)

std::move(b) 传递给foo2 不是一个好主意,因为这会使b 留空并在p 的临时绑定被破坏时删除int 对象。

【讨论】:

    【解决方案2】:

    std::shared_ptr&lt;const int&gt; 是与std::shared_ptr&lt;int&gt; 不同的类型,但有一个隐式转换构造函数。

    当您调用foo2(b) 时,一个临时的std::shared_ptr&lt;const int&gt;b 构造并绑定到p。构造函数增加引用计数,而析构函数减少引用计数。

    当您调用foo1(a) 时,a 被复制到pp 在调用期间存在,然后被破坏。构造函数增加引用计数,而析构函数减少引用计数。

    当您调用foo2(a) 时,a 将绑定到p。没有临时构造,所以引用计数没有改变。

    请注意,您的示例中没有引用计数,因为任何指针都没有指向 ints 或 const ints。

    【讨论】:

    • 没错,我改变了例子,包括一个值。
    猜你喜欢
    • 2015-09-05
    • 1970-01-01
    • 1970-01-01
    • 2012-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-11
    相关资源
    最近更新 更多