CoderAnswer - 程序员编程问答

复制或constref一个shared_ptr?

by @bitmask

c++ performance shared-ptr dereference

考虑一些数据源,它包含shared_ptr(例如结构成员)。如果你保证它不是一个临时值,但是在当前作用域中是有效的,并且你想拥有该指针的别名:哪个是更高效的,复制shared_ptr或者有一个(可能是const)引用原版的?

实施例:

struct S {
  shared_ptr<T> ptr;
};

void fun(S s) {
  shared_ptr<T> alias1 = s.ptr;
  shared_ptr<T> const& alias2 = s.ptr;
  /* do something with the alias */
}

编辑:动机。这可能是必要的,例如1)获取s.ptr涉及遍历一系列函数调用或derefs或2)想要提高可读性。

权衡。复制指针感觉更多"right",因为它模仿你用原始指针做什么,但它需要refcount机制来做它的事情(构造和破坏)。另一方面,有一个你可能经常使用的引用,会产生额外的解除引用,而这又是昂贵的(取消引用是在你使用所持有的T对象做的任何事情之上)。

有一个共同的经验法则是什么更高效?


2个答案

0 by @J. Antonio Perez

经验法则

修改或操作数据而不占用所有权的算法应该作用于迭代器或对数据(或它的容器)的引用。

例如,如果要查找一堆值的平均值,则应编写一个函数,将迭代器作为值集(或通过const引用获取容器)。您不应做的是通过副本传递矢量,或传递智能指针。

复制shared_ptr会产生开销,算法本身应该总是期望他们操作的数据比计算更长。

何时使用shared_ptr编写容器或其他需要在未知时间内保留一段数据的类时,应使用shared_ptr。对象取得所有权,而不是函数,而不是算法。 (当然,成员函数可以接受shared_ptr作为输入,但只有当他们需要拥有该数据的类时才这样做才有意义)。

线程怎么样?

线程是这个经验法则的例外。如果你正在开始一个新线程,你绝对应该按值传递任何shared_ptrs。线程可能存在未知的时间,并且您需要确保它有权访问的任何数据在线程退出之前保持有效。

复制shared_ptr比开始一个线程便宜得多,所以它的开销很小。

0 by @Andy Thomason

SR。 Perez对使用共享指针的最佳方法是正确的。

如果它们被使用,它们应该被明智地用作递增它们 在大多数编译器上,引用计数是一项非常昂贵的业务。

在我工作的一个高调的游戏中,大部分帧时间被一个共享指针取消引用占用。

在示例位掩码中,结构本身是按值传递的,由于copy-elision,它的声音并不像听起来那么糟糕。

https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization

如果你不幸有一个共享指针可以使用,你可以把它变成带有get()的常规指针。

当然,这会让代码不那么安全,但是谁想要一个无聊的生活:)

#include <memory>

struct S {
  std::shared_ptr<int> ptr;
};

void fun(S s) {
    int *alias = s.ptr.get();
    *alias = 1;
}

相关问题