3

指向在 C++ 中以其他方式分配的东西的指针是否合理安全?

到目前为止,我一直在使用 STL 容器(在一种情况下是一个数组,但这是另一个问题)来满足我所有的动态内存需求,所以我不需要显式使用new关键字。我也一直在愉快地使用普通的 ol'int *foo类型指针来引用事物。现在我正在阅读有关智能指针的文章(我在 Java 上切了牙,所以我以前从来不用担心这个),传统观点似乎是“裸指针不好,不要使用它们”。

那么我有多大的麻烦?我可以安全地继续使用裸指针,只要它们指向的东西有其他破坏条件吗?这是我可以逃避但将来应该避免的事情吗?或者我应该匆忙修复它是一场灾难吗?

4

5 回答 5

6

裸指针本身是安全的,它们的错误使用是危险的(而且你很容易被带走)。智能指针很漂亮,但有些 ( shared_ptr) 涉及引用计数,这会导致性能损失。您应该尝试在适用的情况下使用智能指针,但使用指针的 AFAIK 并不被认为是一个可怕的错误。

引用 STL 容器的成员时应该小心,因为它们的地址可能会在重定位期间发生变化,从而给您带来奇怪的错误。

于 2012-05-14T19:28:06.093 回答
1

在编写代码的人和维护代码的人不会犯任何错误的完美世界中,原始指针永远是惊人的。

不幸的是,事实并非如此。首先,裸指针容易出错,指向一些可以在指针不知道的情况下失效的内存,指针可以别名并且它们指向的内容发生变化。

我们实际上需要智能指针来弥补我们的“愚蠢”。至少有些东西必须是“聪明的”:)。

除非你正在做一些非常底层的事情,否则没有必要使用原始指针,仅仅因为它们“不那么聪明”。话虽如此,如果您非常小心,并且在您编写代码后使用您的代码的人非常小心(通常情况并非如此),那么请继续使用原始指针,但除此之外,请使用 smart指针,因为它们只产生很少或没有开销。

unique_ptr<>在您移动它之前没有任何开销,在这种情况下它将一个 NULL 写入内存。在现代编译器上,这经常被优化掉。

shared_ptr<>计算引用并且可能会产生相当大的开销,特别是在多线程应用程序中使用时,但这可以解决,因此并不是一个大问题。

总而言之,没有必要紧急修复原始指针,但我认为不鼓励使用它们。

于 2012-05-14T19:27:52.987 回答
1

说“裸指针不好;不要使用它们”是完全准确的,并附有一个小附录:“指向你必须清理的东西”。

如果您有一个对象并且销毁它是其他人的责任,那么原始指针绝对没问题。但是,当您负责通过任何清理功能销毁对象时,请始终使用智能指针。此外,对于您不清理的对象,请注意在什么情况下它们会被另一个系统函数(本地函数、vector调整大小等)清理。

所有权规则:

  • 无所有权:T*,并注意何时不能再使用它
  • 共享所有权:shared_ptr<T>,如有必要,使用自定义删除器
  • 唯一所有权:unique_ptr<T, Del>,如有必要,自定义删除器

始终遵循这些规则,您将永远不会有任何内存泄漏、双重释放、错误的指针访问或任何类似的与内存相关的错误。

于 2012-05-14T19:31:38.733 回答
0

裸指针被认为是不好的,因为它们很容易陷入困境。智能指针会自动为您处理一些问题,这使得它们不太容易出错。

当您对所有代码拥有绝对控制权(即,您是项目中唯一的编码员)时,只要您遵循基本的内存分配法律和惯例(“分配内存的人就摆脱它),使用裸指针就可以了除非另有说明。”)。但是,当您与其他人一起编写代码时(即,有超过 1 名编码员的项目),这就为错误和误解打开了大门。

智能指针负责谁拥有一个对象(因此谁应该释放它)。他们还可以跟踪使用该对象的最后一个代码何时不再需要它,因此可以在共享分配的数据时安全地释放它。

引用计数的智能指针还为从堆中分配内存的类的那些数据成员生成安全的默认复制构造函数和安全的默认复制赋值运算符。他们可以安全地将他们的引用计数智能指针设置为他们正在复制的原始对象,并且当原始对象或克隆超出范围/被删除时,他们通过智能指针管理和共享的分配内存将留给仍然指向它的其他对象。这不适用于裸指针。如果使用裸指针,则必须编写复制赋值运算符和复制构造函数来克隆分配内存的对象,以防止包含/拥有的分配数据的数据损坏。

于 2012-05-14T19:58:26.480 回答
-2

当你不用担心太多的时候new,裸指针是不好的。delete这种行为可能会导致您出现非常奇怪的错误。我的建议是,当您必须使用在堆上分配的几个指针和对象时,学习使用内存泄漏检查器Valgrind

然后是一些简单的规则,当你用 then 实例化数组时,new []你总是必须用 then 删除它们,delete []反之,当你用newthen 实例化单个对象时,总是 call delete

记住要避免混合new- deletewith malloc-free或 with new[]-delete[]因为这些功能不是为了相互配合而设计的,例如永远不要这样做:

int *a = (int*)malloc(10*sizeof(int));
delete a;

但是这个

int *a = new int[10];
delete[] a;

正如 Tibor 所说,指针的使用本身并不错,但一如既往,“能力越大,责任越大”:P

于 2012-05-14T19:34:37.013 回答