函数类型之间的差异

Difference between function types

本文关键字:之间 类型 函数      更新时间:2023-10-16

它们之间有什么区别?

MyType myFunction();
MyType t = myFunction();

MyType &myFunction();
MyType t = myFunction();

const MyType &myFunction();
MyType t = myFunction();

幕后发生了什么?

在这三种情况下,第二行是常见的:

MyType t = myFunction();

该行获得调用myFunction的结果,并使用它来复制构造MyType的一个名为t的新元素。

现在谈谈差异。在第一种情况下,您按值返回,这意味着(语义上)编译器将在myFunction内的return语句中创建对象的副本,然后将该副本用作t的副本构造的源。编译器很可能会删除副本(至少第二个)。

在其他两种情况下,函数返回对其他对象的引用。如果对象是局部对象,则为"未定义行为"。两者之间的区别在于返回的引用是否可以用于修改引用的对象,这可能会影响使用什么复制构造函数,或者是否可以使用它。请注意,从中获取引用的对象必须比函数调用更长寿,否则将导致未定义的行为。

// an example where it matters:
typedef std::auto_ptr<int> MyType;
MyType t = myFunction();

因为std::auto_ptr修改了赋值的右侧,所以只有当返回的引用是非常量时,前面的代码才会起作用。

Luchian指出,返回引用很可能是未定义的行为,那么什么时候不会呢?当从中获取引用的对象超过引用的使用寿命时。这是Meyers单例的基本构建块:

// an example where returning a reference is correct
MyType & myFunction() {
  static MyType instance;   // Note static storage duration!
  return instance;
}

或者任何返回对子对象引用的普通访问器。一些常见的情况是容器中的operator[](它们通常不复制值,而是返回对存储数据的引用)。

但事实上,函数通常不会返回静态的对象,而是返回局部对象。

我假设这些是自由函数。

MyType myFunction();
MyType t = myFunction();

按值返回一个MyType对象。理论上,在myFunction中创建的对象在返回时被复制。实际上,RVO最有可能发生。

MyType &myFunction();
MyType t = myFunction();

通过引用返回。这很可能是未定义的行为,因为通过引用返回本地对象是非法的。但是,如果myFunctions是一个成员函数,那么您可以返回一个MyType,它是该类的一个成员,只要实例的寿命比t长就可以了。

对于第二个代码片段,您应该得到一个警告——"通过引用返回局部变量"或类似的内容。

除了一个小细节外,大多数答案都是正确的。

const MyType& t = myFunction();

看起来,如果myFunction()返回一个临时变量,这将是未定义的行为,但事实并非如此。这不是UB,事实上const引用将临时的生存期扩展到const引用的生存期。事实上,这是最有可能进行编译器优化的版本,也提供了一个重要的教训,即在可能的情况下,应该始终将返回值放入常量引用中。

我想你想做的是:

MyType *myFuntion()
{
  MyType *t = new MyType;
  // do something with t
  return t;
}
// ... somewhere else ...
MyType *t = myFunction();

即在函数中构造一个新对象并返回一个指向它的指针。不要忘记调用

 delete t;

稍后的某个地方!