auto_ptr
的意义是什么?
看看这段代码:
#include <iostream>
#include <memory>
class A
{
public:
~A()
{
std::cout << "DEST";
};
};
void func(A* pa)
{
std::cout << "A pointer";
}
void test()
{
A a;
std::auto_ptr<A> pA(new A);
//func(pA); //compiler error here cannot convert parameter 1 from 'std::auto_ptr<_Ty>' to 'A *'
std::cout << "end";
}
int main(int argc, char* argv[])
{
test();
return 0;
}
使用此auto_ptr
有什么意义?
auto_ptr
用于A[]
或char[]
,因为auto_ptr调用不会删除delete[]
。唯一的想法是我不必编写删除,但是当我超出范围时它是否会被销毁时会产生指针感。我使用指针来控制变量的实时。
普通变量initialize在堆栈上,指针在堆上,但告诉我使用auto_ptr
而不是正常指针的意义是什么?
答案 0 :(得分:5)
唯一的想法是我不必写删除
是的,考虑到内存泄漏是一个非常大的好处,这是你将遇到的最常见的错误之一。
当我超出范围时,指针的意义是什么?我使用指针来控制变量的实时。
你从这种心态转变并使用范围来定义变量的生命。您只需在适当的范围内声明这些内容,而不必担心清理。这就是重点。
你的例子是人为的,但你仍然可以看出为什么它有价值。当然,您可能不会忘记在两行函数中调用delete
,它根本不执行任何操作。在实际应用中,事情变得更加复杂。
当你new
一堆对象时,你可以依赖这样一个事实:当函数退出时,对象将被清理掉。课程也是如此;当一个实例超出范围时,你可以依靠它的析构函数来为你解除内存释放。考虑抛出异常时会发生什么。如果没有auto_ptr,你需要确保你处理每一个可能的异常和每个可能的返回路径,以确保你自己清理。
也...
正常变量initialize在堆栈上,指针在堆
上
不完全。在这种情况下,指针具有自动存储持续时间,它指向然而不是。
你的编译器在传递auto_ptr
时咆哮的原因是因为该函数没有使用auto_ptr
。你需要调用get()
传入指针本身。
那就是说,你也不应该使用auto_ptr
;如果您有权访问C ++ 0x编译器,请使用unique_ptr。
答案 1 :(得分:4)
使用auto_ptr
(或其他智能指针)来管理内存有很多原因。我们改变那段代码:
void test()
{
A a;
std::auto_ptr<A> pA(new A);
if(SomeFunc())
return;
//func(pA); //compiler error here cannot convert parameter 1 from 'std::auto_ptr<_Ty>' to 'A *'
std::cout << "end";
}
如果pA
不是智能指针,我们现在会发生内存泄漏。但是因为它是,我们知道将正确释放内存。没什么值得担心的。如果SomeFunc
抛出异常,它仍然会被释放。
要解决有关传递指针的问题,请执行以下操作:
void test()
{
A a;
std::auto_ptr<A> pA(new A);
func(pA.get());
std::cout << "end";
}
pA
对象仍然拥有内存; func
不得删除,且不得存储。
答案 2 :(得分:3)
请记住,std::auto_ptr
有许多缺点,如果您的编译器提供它,通常应该使用std::unique_ptr
。 (如果没有,请更新编译器!:))
现在回到你的问题......
是什么意思使用这个auto_ptr?它在超出范围时调用类析构函数作为普通类初始化变量(a)
完全。 auto_ptr
的原因是强制执行严格的所有权语义 - 以便在指针本身被销毁时正确销毁对象。
我无法将此指针传递给具有类指针(func)
的函数
您可以,您需要使用get()
来查找原始指针。将指针传递给函数调用时使用get()
意味着该函数不会取得对象的所有权(auto_ptr
仍然拥有它并期望它在函数返回后仍然有效)。
或者,您可以在指针上使用release()
来获取原始指针,并指示auto_ptr
不再负责对象的所有权。
是的,这是一个问题。这是自我无法将指针auto_ptr用于A []或char [],因为auto_ptr调用delete而不是delete []
auto_ptr
引入以来不再使用unique_ptr
的原因之一。它做同样的事情,但更安全(=更容易)使用和更多功能。
唯一的想法是我不必编写删除,但是当我超出范围时它是否会被驱逐,那么指针的感觉是什么。
这样你就不会忘记它:-)或者你可以使用auto_ptr
(或更好的unique_ptr
作为类对象中的成员。)
但请告诉我使用auto_ptr而不是正常指针的意义是什么?
长话短说:许多指针可以指向单个对象。 存在各种智能指针,使用类型系统进行簿记,指针拥有对象(=负责释放它)。
如果你有一个(可能)拥有另一个对象实例的类,你只需写:
class X {
// ...
X() : ptr(new Type()) {}
X(Type ptr) : ptr(ptr) {}
// ...
void setPtr(Type ptr2) { ptr.reset(ptr); }
// ...
std::unique_ptr<Type> ptr;
};
如果设置了ptr
,那么例如unique_ptr
的析构函数将负责删除对象(如果有的话)。在setPtr
方法中,reset()
函数将删除旧实例(如果有)并将成员设置为提供的新实例(或者为null - 这没关系。)
现在比较另一种情况:
class X {
// ...
X() : ptr(new Type()) {}
X(Type ptr) : ptr(ptr) {}
// ...
void setPtr(Type ptr2) {delete ptr; ptr = ptr2;}
// ...
Type* ptr;
};
同样的行为?没有!因为现在,为了拥有安全的C ++代码,您还需要编写一个析构函数,以便在ptr
被销毁时删除X
。
Unique_ptr不允许您隐式复制X对象以及对ptr
的强引用,因为unique_ptr是不可复制的(它认为它是对象的唯一unique_ptr,所以它是只有智能指针实例负责删除它 - 但是如果原始的,非拥有的指针指向它,只要它们不尝试删除它们不拥有的东西就可以了!)。
这不是全部 - unique_ptr无法复制,但它有一个移动构造函数和移动赋值运算符为您准备好了!因此,您可以安全地从函数等返回它。
这就是智能指针的类型安全性如何转化为编写更安全的代码。
黄金法则:尽量避免编写“删除”(除非您正在编写自己的容器或智能指针)。 :)
答案 3 :(得分:2)
如果您能够在堆栈中创建所有对象,那么就不需要auto_ptr
。但想想:
auto_ptr
以防止内存泄漏,期间)第二个想法,你应该read Herb Sutter on this。他比我更了解。 ; - )
答案 4 :(得分:1)
这是正确的方法:
void test()
{
A a;
std::auto_ptr<A> pA(new A);
func(pA.get());
std::cout << "end";
}
如果函数func
抛出异常,auto_ptr
会在超出范围时自动释放内存。