与普通指针相比,使用自动指针(auto_ptr)有哪些优缺点?我听说它会自动释放内存,但为什么不经常使用?
9 回答
的主要缺点std::auto_ptr
是它具有所有权转移语义。这使得存储std::auto_ptr
在 STL 容器中变得不可能,因为容器在存储或获取元素时使用复制构造函数。
此外,我注意到的另一个重要方面std::auto_ptr
是它们不能用于PIMPL成语的使用。这是因为,它们需要包装类的析构函数的完整定义。有关更详细的讨论,请参阅clc++.m 上的此线程。
更新:所有权转让
class Test {};
std::auto_ptr<Test> ap_test_1(new Test);
std::auto_ptr<Test> ap_test_2(new Test);
ap_test_2 = ap_test_1; // here ap_test_1's ownership is transferred i.e. ap_test_2 is the
// new owner and ap_test_1 is NULL.
有关在 STL 算法使用的 STL 容器中使用这意味着什么的更多详细信息,请参阅Herb Sutter 网站上的此线程。
智能指针在 C++中经常使用,尽管可能没有应有的频繁使用。有std::auto_ptr
一些问题(例如,您不能在标准库集合中使用它),但还有很多其他问题。其中最受欢迎的是Boost 库附带的,它将成为下一个 C++ 标准的一部分——你应该看看。
请注意,智能指针主要与所有权有关,并删除动态创建的对象。如果您没有动态创建的对象,则通常不需要智能指针:
{
int i = 42;
auto_ptr <int> p( & i ); // bad!
}
你真的不想这样做,因为当自动指针超出范围时,它会尝试删除 i。不幸的是,我不是动态创建的,所以会发生不好的事情。因此,在大多数 C++ 程序中,您需要两种类型的指针,智能指针和普通指针。
也许它没有被广泛使用的最大原因是:
std::auto_ptr 有一个巨大的缺点:它不能在不破坏的情况下被复制。当您需要复制自动指针时,原始实例将被销毁。这意味着您在任何时候都可能只有一个对象副本。这也意味着 auto_ptr 不能与标准容器一起使用,例如 vector、deque、list、set 和 map。事实上,它几乎不能用于任何依赖复制构造的类。
此外, auto_ptr 也不安全,因为没有什么可以阻止您意外地进行复制。如果你这样做,你会破坏原始副本。此外,一些不太符合标准的 C++ 编译器允许您将声明的对象存储在 auto_ptr 中,并在不包含类的完整定义的情况下使用它。这总是会导致内存泄漏。
auto_ptr 存在的主要理由是以异常安全的方式转移所有权。尽管大多数人将其用作穷人的 boost::scoped_ptr。
主要用途是使用对象指针作为参数或返回值返回的函数。
例如工厂函数
std::auto_ptr<MyClass> createMyClass(MyClass::Type type) {
if (type == MyClass::TypeOne) {
return std::auto_ptr(new MyClassOne);
}
else {
return std::auto_ptr(new MyClassTwo);
}
}
void foo() {
std::auto_ptr<MyClass> myc = createMyClass(MyClass::TypeOne);
// use myc
}
虽然这段代码非常简单,并且如果抛出异常则不应抛出异常 myc 正确处理它,但使用原始指针执行此操作会很困难。
boost::shared_ptr 也可以使用,但这提供了比所需更多的功能,它还表明您希望共享对象。使用 auto_ptr 的地方更简单,并且您清楚地表明您正在转移所有权。
最近有人告诉我 boost::unique_ptr 似乎与 auto_ptr 具有相同的用法,但没有缺点。
查看返回智能指针时的最佳实践以获取更多信息
不要将自动指针 (std::auto_ptr) 与智能指针系列(尤其是 std::auto_ptr、boost::scoped_ptr 和 boost::shared_ptr)混淆。
我几乎从不使用自动指针,因为大多数时候,我宁愿使用引用。我做的唯一一次是不能在对象的构造函数中实例化的成员变量。
相反,智能指针非常强大,但这不是你的问题,我猜 :)
优点是简单的使用,他们做他们的工作。
void foo() {
std::auto_ptr<int> bar(new int);
// do the stuff that potentially throw
} // the auto_ptr destructor will call delete here
缺点是一旦你摆脱了这种简单的使用,你就会遇到 auto_ptr 的坏语义。
std::auto_ptr<int> foo(new int);
std::auto_ptr<int> bar = foo; // foo is changed here! It does not have ownership anymore.
最好使用具有良好语义的 unique_ptr 和 shared_ptr,它们在 boost:: 中可用,并且在下一个 C++ 标准中将在 std:: 中可用
auto_ptr
可以用于多种用途,但我认为最好的用途是在堆上分配对象并在退出范围堆栈帧时释放它们的工具。
恕我直言,唯一真正的问题auto_ptr
是名称。人们看着它并认为它是一个智能指针,当然不是。
如果我们这样称呼它,AutoDelete<T>
也许我们会进行不同类型的讨论。:-)
简短的故事: std::auto_ptr 不能共享,常规指针可以。
auto_ptr 具有它指向的对象的所有权模型。您不能对同一个对象有多个引用,也不能将它们放在 stl 容器等中 - 看起来确实是在转移所有权的代码,并且会在生产中导致令人讨厌的难以追踪的错误。
boost 的shared_ptr在几乎所有情况下都更加实用。