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++标准允许编译器进行这种优化,即使它打破了规则,就好像一样。我很久没有遇到过一个编译器不会在这种表达式中删除副本:
Person p = getPerson();
在C++11中,即使没有拷贝省略,这也是move构造的候选者。这个可能是一个非常便宜的操作,但这实际上取决于所讨论的类型。无论如何,复制省略是很难避免的。
请参阅此相关帖子。
请参阅此演示。
正如其他人已经指出的,返回值优化有助于最大限度地减少简单返回值对性能的影响。
移动语义(C++11中的新语义)在这方面也有帮助——返回表达式几乎是"xvalue"的典型示例,它可以将其值从源移动到目标,而不是复制。特别是对于主要由指向真实数据的指针组成的类型(例如向量),这可能是非常有益的,因为它本质上允许浅拷贝而不是深度拷贝(即,它不是复制整个向量,而是只复制指针)。
shared_ptr或unique_ptr也可以在这里工作。shared_ptr基本上是一个引用计数的指针,因此(C++11之前)它允许您通过在返回过程中增加引用计数,然后再次减少引用计数来保持对象的活力。至少在单线程环境中,这通常非常便宜——通常比制作数据副本便宜。
unique_ptr可以做大致类似的事情,但没有增加和减少引用计数的开销。基本的区别在于,它不是让复制变得便宜,而是移动指针来避免复制。
其中任何一个都可以工作,但很明显,在大多数情况下,最好的方法就是只返回值(如果有意义,可以在您使用的类型中添加一个移动构造函数和/或移动赋值运算符)。
一旦函数执行完成,局部变量就会超出范围-它们的生存期结束。因此,通常情况下,返回对局部变量的引用或指针不是一个好主意。
您可能想要做的是返回对类成员变量的引用或指针,只要类对象在作用域中或具有有效的生存期,这些变量就会保持其生存期。
如果您需要返回多态对象,我建议使用唯一指针:
std::unique_ptr<Person> getPerson()
{
return std::unique_ptr<Person>(new Programmer);
}
我知道我经常谈论这件事。
另一种选择是不归还任何东西。
告诉对象该做什么:
- 使用此渲染器显示您自己
- 使用这个serializer序列化您自己(实现可以是xml、数据库、json、网络)
- 更新您这次的状态
- 使用这个控件创建者(创建滑块、下拉列表、复选框等),用控件装饰自己
总的来说,不需要吸气器。努力避免它们,你会发现你的设计发生了令人愉快的变化,可测试,合理。
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 初始化或分配空字符串文字到指向 C 中的 char 的指针或指向 C++ 中 const char 的指针的原因是什么
- int数据类型的指针指向的是什么,如果是一个类的私有数据成员,我们创建了该类的两个对象?
- 使用基类指针调用基类的值构造函数的语法是什么?
- C++:Lambda 函数指针转换的用例是什么?
- C++关于指针和使用函数将它们启动到堆的行为究竟是什么?
- 使用共享指针时,从共享指针本身释放内存的机制是什么
- 为什么此指针值不能转换为整数的规则是什么?
- 在自定义 std::vector-like 容器中处理指针和非指针模板类型的最佳方法是什么?
- 回调和函数指针是什么关系
- 带有'this'的空指针是什么意思?
- 将对象传递给将创建它的函数时,要使用的合适的智能指针是什么
- 与自定义分配器一起使用的最佳唯一指针是什么
- 检测"内存泄漏"时,瓦尔格林德的真实指针是什么?
- 类指针*是什么意思
- 指向指针的指针是什么意思
- c语言中的远函数指针是什么,它的语法是什么
- 与指针向量一起使用的最佳智能指针是什么
- a=&*A 在 C++(其中 A 是指针)是什么意思?
- C++中的富指针是什么