指向以其他方式分配的东西在C ++中是否合理安全?
到目前为止,我一直在使用STL容器(在一种情况下,一个数组,但这是另一个问题)满足我所有的动态内存需求,因此我不需要显式使用{{1} }关键字。我也很乐意使用简单的'new
类型指针来引用事物。现在我正在阅读有关智能指针的内容(我在Java上切入了牙齿,所以我以前从未担心过这种情况)而传统的智慧似乎是“裸指针很糟糕,不要使用它们。”
那我有多麻烦?我可以安全地继续使用裸指针,只要它们指向的东西有其他破坏条件吗?这是我可以逃避的事情,但将来应该避免吗?或者这是一场灾难,我应该在匆忙之后解决这个问题?
答案 0 :(得分:6)
裸露的指针本身是安全的,这是错误的使用它们是危险的(并且你可以轻易地被带走)。智能指针很漂亮,但有些(shared_ptr
)涉及引用计数,这会导致性能损失。您应该尝试使用适用的智能指针,但AFAIK使用指针不被认为是一个可怕的错误。
引用STL容器的成员时应该小心,因为它们的地址在重定位期间可能会发生变化,从而使您遇到奇怪的错误。
答案 1 :(得分:1)
在一个完美的世界里,编写代码的人和维护它的人不会犯任何错误,原始指针是惊人的。
不幸的是,事实并非如此。首先,裸指针容易出错,指向一些内存,如果没有指针知道它就可以失效,指针可以是别名的,它们指向的内容也会改变。
我们实际上需要智能指针来弥补我们的“愚蠢”。至少有些东西必须“聪明”:)。
除非你正在做一些非常有用的事情,否则不需要使用原始指针,因为它们“不那么聪明”。话虽如此,如果你非常小心,并且在你编写代码后使用代码的人非常小心(通常情况往往不是这样),那么继续使用原始指针,但除此之外,使用智能指针,因为它们只产生很少或没有开销。
unique_ptr<>
没有任何开销,直到你移动它,在这种情况下它会将一个NULL写入内存。在现代编译器上,这经常被优化。
shared_ptr<>
计算引用并且可能产生相当大的开销,特别是在多线程应用程序中使用时,但这可以解决,因此不是一个如此大的破坏者。
总而言之,没有必要紧急修复原始指针,但我认为不鼓励使用它们。
答案 2 :(得分:1)
完全准确地说“裸指针是坏的;不要使用它们”附带一个小小的附录:“指出你必须清理的东西”。
如果你有一个对象而且其他人有责任销毁它,那么原始指针绝对没问题。但是,当您负责通过任何清理功能销毁对象时,请始终使用智能指针。此外,对于您不清理的对象,请注意在其他系统功能本地人清理它们的条件下,vector
调整大小等。
所有权规则:
T*
,请注意何时无法再使用shared_ptr<T>
,必要时使用自定义删除unique_ptr<T, Del>
,必要时自定义删除始终遵循这些规则,您将永远不会有任何内存泄漏,双重释放,错误的指针访问或任何类似的内存相关错误。
答案 3 :(得分:0)
裸指针被认为是坏的,因为很容易与它们发生问题。智能指针会自动处理一些问题,这使它们不容易出错。
当你完全控制所有代码时(即,你是项目中唯一的编码器),只要遵循基本的内存分配法则和惯例(“无论谁分配内存”,使用裸指针都可以。除非另有说明,否则除掉它。“)。但是当你与其他人一起处理代码时(例如,有超过1个编码器的项目),就会打开错误和误解的大门。
智能指针负责拥有对象的人(因此谁应该解除分配对象)。它们还可以跟踪使用该对象的最后一个代码何时不再需要它,因此可以在共享分配的数据时安全地释放它。
引用count的智能指针还会为从堆中分配内存的类的数据成员生成安全的默认复制构造函数和安全的默认复制赋值运算符。他们可以安全地设置他们的引用计数智能指针到他们正在复制的原始对象,当原始或克隆超出范围/被删除时,他们通过智能指针管理和共享的分配内存留在其他仍然指向它的对象。裸指针不是这样。如果使用裸指针,则必须编写复制赋值运算符和复制构造函数来克隆分配内存的对象,以防止包含/拥有的已分配数据的数据损坏。
答案 4 :(得分:-2)
当new
和delete
没有太多担心时,裸指针很糟糕。此行为可能会导致您出现非常奇怪的错误。我建议,当你必须使用堆上分配的几个指针和对象时,要学习使用内存泄漏检查器 Valgrind 。
然后是一些简单的规则,当您使用new []
实例化数组时,您始终必须使用delete []
删除它们,相反,当您使用new
实例化单个对象时,请始终调用{{1 }}
请务必避免将delete
- new
与delete
- malloc
或free
- new[]
混在一起,因为这些功能并非设计为彼此合作,例如从不这样做:
delete[]
但是这个
int *a = (int*)malloc(10*sizeof(int));
delete a;
正如蒂博尔所说,指针的使用本身并不坏,但一如既往,“以强大的力量来承担巨大的责任”:P