繁体   English   中英

在C ++中返回局部变量的引用和标准指针的替代方法是什么?

[英]What are the alternatives to references and standard pointers for returning local variables in C++?

我对C ++相当陌生,我知道三种返回局部变量的方法,但都有缺点:

Person& getPerson()
{
   Person bob;
   return bob;
}

显然不是一个好主意。

Person getPerson()
{
   Person bob;
   return bob;
}

空指针或悬空引用没有机会,但会降低性能。

Person* getPerson()
{
   return new Person();
}

空指针没有机会,但是肯定会违反OO设计的基本规则。 另一个对象将不得不删除它-但是为什么必须删除它呢? getPerson()方法的实现与它无关。

因此,我正在寻找替代方案。 我听说过共享指针和智能指针(标准指针和Boost指针),但是我不确定它们中的任何一个是否旨在解决此问题。 你们有什么建议?

选项2:按值返回。

Person getPerson()
{
  Person bob;
  return bob;
}

这里没有性能受到影响。 您的编译器可能会(并且可能会)删除此副本。 实际上,即使您关闭了编译器的复制删除优化,对于C ++ 11编译器,这也将被视为先行一步。

实际上,即使您随后执行Person p = getPerson()通常会涉及两个副本), 可能会忽略两者

参见§12.9/ 31:

在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv不合格类型的非易失性自动对象(函数或catch子句参数除外)的名称时,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作

和§12.9/ 32:

当满足或将要执行复制操作的省略标准时,除非源对象是函数参数,并且要复制的对象由左值指定,否则重载分辨率为复制选择了构造函数首先执行,就好像该对象是由右值指定的。

空指针或悬空引用没有机会,但会降低性能。

实际上,根本不影响性能。 参见示例: 想要速度吗? 价值传递

编译器可以使用称为复制删除和命名返回值优化的策略轻松地对此进行优化(请参阅该链接)。

您不必担心此处的性能下降:

Person getPerson()
{
   Person bob;
   return bob;
}

您担心的副本很可能会被隐藏在所谓的返回值优化(RVO)中 C ++标准允许编译器进行此优化,即使它违反了as-if规则。 我很长一段时间都没有遇到过不会编译掉这种表达式的副本的编译器:

Person p = getPerson();

在C ++ 11中,即使没有复制省略,也可以作为移动构造的候选对象。 可能是一个非常便宜的操作,但实际上取决于所讨论的类型。 无论如何,都很难避免复制省略。

请参阅此相关文章

看到这个演示

正如其他人已经指出的那样,返回值优化有助于最小化简单返回值所带来的性能损失。

移动语义学(C ++ 11中的新增功能)在这方面也可以提供帮助-返回表达式几乎是“ xvalue”的典型示例,它有资格将其值从源移动到目标,而不是复制。 特别是对于主要由指向实际数据的指针组成的类型(例如向量),这可能是非常有益的,因为它本质上允许使用浅表副本而不是深表副本(即,而不是对整个向量进行复制) ,只会结束复制指针)。

shared_ptr或unique_ptr也可以在这里工作。 shared_ptr本质上是一个引用计数的指针,因此(C ++ 11之前的版本)它使您可以通过在返回过程中仅增加引用计数,然后再将其递减来保持对象活动。 至少在单线程环境中,这通常很便宜-通常比制作数据副本便宜。

unique_ptr做大致相似的事情,但是没有增加和减少引用计数的开销。 基本的区别在于,它使指针移动以完全避免进行复制,而不是使复制变得便宜。

这些方法中的任何一种都可以使用,但是很明显,在大多数情况下,它们中的最佳方法是仅返回值(如果有意义,请向要使用的类型添加move构造函数和/或move赋值运算符)。

一旦函数执行完成,局部变量将超出范围-它们的生命周期结束。 因此,通常不建议返回对局部变量的引用或指针。

您可能想做的是返回对类成员变量的引用或指针,只要类对象在作用域内或具有有效的生存期,它们就可以维持其生存期。

如果您需要返回多态对象,我建议使用唯一的指针:

std::unique_ptr<Person> getPerson()
{
    return std::unique_ptr<Person>(new Programmer);
}

我知道我对此事很感兴趣。

另一种选择是不返回任何内容。

告诉对象该怎么做:

  • 使用此渲染器显示自己
  • 使用此序列化器序列化自己(实现可以是xml,数据库,json,网络)
  • 这次更新您的状态
  • 使用此控件创建者为控件装饰自己(创建滑块,下拉列表,复选框等)

总体上不需要吸气剂。 尽力避免它们,您会发现您的设计令人愉快地更改,可测试,合理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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