0

我们使用 C++98(旧版本)。

假设我们有一个表并考虑查找。Ptr 是一些智能指针。从调用者的角度来看,以下语句 1. - .3 是否正确或考虑的两种情况同样安全/不安全?

查找函数原型:

const Y::Ptr & lookup(const X::Ptr & x);

以及调用查找的调用者函数:

const Y::Ptr & ret = lookup(x);

其中 x 是 X::Ptr 对象或 X::Ptr 的引用。因此,基于上面的 2 行,我们有以下用法。

  1. 函数参数const X::Ptr &。这通常是安全的,并且避免X::Ptr了函数调用时的复制构造函数。调用者负责在查找函数调用期间保持X对象的引用X以持续。
  2. 返回值const Y::Ptr &。这是不安全的,因为在此引用在堆栈上的短暂持续时间内,如果线程被中断/挂起并且另一个线程从表中删除条目,则 Y 对象和Y::Ptr对象都将被删除。结果,Y::Ptr堆栈上的引用引用了一个消失的 Ptr 对象。
  3. const Y::Ptr &用于存储查找返回值的本地引用。这不安全,原因与 #2 类似,但可能更糟,因为调用者函数中的本地引用的范围比堆栈上作为返回值的 ref 更长。
4

2 回答 2

0

我认为你说得对。显然,一个解决方案是按值返回智能指针。请注意,您的第 2 点完全包含在第 3 点中,因此没有太多需要专门考虑第 2 点(因为您没有-或不能-使用的参考没有意义)。

于 2013-10-17T12:36:04.783 回答
0

很大程度上取决于做什么lookup以及您要达到的目标。您是在逻辑上返回一个值,还是对某些内部数据的引用?在许多函数名称如 的情况下lookup,它是后者,并且返回值作为引用通常很重要。(一个明显的例子是类似operator[]in的函数std::vector。)除非语义需要引用,否则最好按值返回。

类似的,在呼叫站点。如果调用者需要对您的数据结构的引用,他应该将变量声明为引用;否则,他应该将其声明为一个值。(当然,如果函数返回一个值,那么局部变量应该是一个引用是绝对不可能的。)

我认为多线程在这里是一个红鲱鱼。如果其他线程正在修改lookup使用的数据结构,则需要外部同步,期间。如果函数返回一个引用,并且您将其保留为引用,则临界区包括引用的生命周期,但这通常不是大问题;如果是,调用者可以将结果存储为一个值,并完成它。

作为一般规则,C++ 更喜欢值语义。考虑到这一点,该语言进行了优化,包括允许编译器优化不必要的副本的特殊规则。不要与之抗争。唯一的例外是使用 const对函数参数的引用。(但即使在这里,您也希望保持一致。普遍的约定是通过引用 const 来传递类类型,通过值传递其他类型。如果这是您的代码中使用的规则,那么系统地使用它,无一例外。)

于 2013-10-17T13:22:58.670 回答