假设有一个函数接受引用(&)变量作为参数形式。调用方可以传递一个本地变量或指针(*ptr)。被调用函数可能会拷贝传入对象的数据。
这个问题是我之前关于C++ Bada开发的问题的后续。
delete
是代码异味的一个非常明显的迹象,除非你恰好实现了一个智能指针(或垃圾回收)库。在所有其他情况下,它都是不合适的。 - Konrad Rudolph创建对象的方式取决于您打算用它做什么。
如果您使用new
语句创建对象,则会得到指向手动分配对象的指针。只要不使用delete
手动释放,该对象将一直存在。
如果您在堆栈上创建一个简单对象,则只要当前堆栈被使用,即作用域未改变,该对象就会一直存在。
常见库(如STL)将允许这两种对象。
如果库有特殊要求,则必须在某个地方记录下来,并且主要解释是因为它想拥有该对象。
不存在所谓的“简单对象”。一个对象就是一个对象。
重要的是对象的生命周期:自动(作用域),动态(手动)或静态(永久)。
尽量使用具有自动生命周期的对象,除非你有一个真正很好的理由去使用其他类型。
如果你考虑一个对象如何依赖于另一个对象,你会发现,如果你只使用自动对象,那么你不会遇到悬空引用的问题(或者说“对局部变量的引用”),因为依赖对象的作用域比被引用对象更深。
你应该有一个非常有说服力的理由,说明为什么一个特定的对象必须具有手动生命周期。当然,这些情况确实会发生,但它们应该被抽象化和分解。例如,大多数标准库容器当然需要手动管理它们的元素,但所有这些都由容器处理,因此用户可以只使用自动生命周期的容器对象,一切都很好。最后,如果你决定真的必须手动管理对象的生命周期,那么使用单一职责资源管理类,如shared_ptr
或unique_ptr
来传递该对象的句柄--处理程序类现在又变成了自动的,一旦它们超出作用域,它们就会为您释放托管对象。你得到了最好的两个世界:手动对象分配的好处和范围责任。
如果你按照这些思路有条不紊地工作,你会发现自己很少创建动态对象,而且如果你这样做了,只需要一行相关的代码(这使得你“局部化”);例如,auto p = std::make_shared<T>(a,b,c);
或者 std::unique_ptr<T> p(new T(a,b,c));
。在所有源代码上进行简单的 grep
查找 new
就可以轻松审计是否负责处理了所有动态分配。
有很多事情需要考虑。当决定是否使用指针时,寿命、多态性、引用和性能都是需要考虑的因素。
正如其他人所说,堆栈空间具有作用域寿命。一旦变量超出范围,它就完成了。通过指针分配的内存将持续到调用delete为止,但请记住指针本身仍将超出范围!因此,请确保在某个地方保留引用!
至于多态性,使用堆栈空间会导致切片问题不可能发生。因此,如果您需要使用此技术,请坚持使用指针。
引用应该是显而易见的。您需要将相同的内存移动到程序中的各个位置吗?多个事物需要访问完全相同的内存,而不仅仅是副本吗?
最后,性能。使用堆内存会给您带来性能损失吗?指针较慢,因为需要额外的分配时间。它们还需要一些额外的内存来存储指针本身(实际上微不足道,但您可能也要考虑一下。这真的取决于您的应用程序)。