在下面的示例中,如何在C ++中使用智能指针

时间:2012-02-27 17:00:23

标签: c++ smart-pointers

我正在阅读C ++中的智能指针,并看到这个例子给出了如果使用普通指针,智能指针如何处理“悬空指针”问题。附:我知道auto_ptr已经被C ++ 2011弃用了,但它仍然有unique_ptr或者它的一些等价物。

悬空指针。常规指针的常见缺陷是悬空指针:指向已删除对象的指针。以下代码(例如jsut)说明了这种情况:

    MyClass* p(new MyClass);//Assume we have a MyClass definition available
    MyClass* q = p;
    delete p;
    p->DoSomething();   
    p = NULL;           // p is not dangling anymore
    q->DoSomething();   // Don't.. q is still dangling!

使用auto_ptr,这可以通过在复制时将其指针设置为NULL来解决(复制构造函数实现如下):

template <class T>
auto_ptr<T>& auto_ptr<T>::operator=(auto_ptr<T>& rhs)
{
    if (this != &rhs) {
        delete ptr;
        ptr = rhs.ptr;
        rhs.ptr = NULL;
    }
    return *this;
}

现在如果我们使用auto_ptr具有相同的代码,如下所示:

auto_ptr<MyClass> p(new MyClass);
auto_ptr<MyClass> q = p;
delete p;
p->DoSomething();   
p = NULL;           
q->DoSomething();   

我在aqbove复制构造函数中得到了逻辑但是如何使rhs.ptr = NULL有帮助。我的意思是如果稍后一个解引用此指针(上面的代码示例中的q),它将崩溃,因为它由智能指针复制构造函数使其为NULL。

如果它是一个正常的指针而发生了什么,我们会取消引用一个悬空指针?一些未定义的行为可能。但是如何使用auto_ptr帮助

5 个答案:

答案 0 :(得分:9)

智能指针不一定会保护你,如果你取消引用它们而不先检查它们;他们给你的是保证你在解除引用之前可以检查它们是否有效。

悬空指针的问题在于它没有指向任何有效的东西,但没有办法说出来:

Thing * p = new Thing;
Thing * q = p;

if (p) p->DoSomething(); // OK: checks p, calls function
if (q) q->DoSomething(); // OK: checks q, calls function

delete p;
p = nullptr;

if (p) p->DoSomething(); // OK: checks p, does nothing
if (q) q->DoSomething(); // BOOM! Undefined behaviour

使用智能指针,你永远不会有这种情况;指针有效,或者在解除引用之前可以告诉它无效:

auto_ptr<Thing> p(new Thing);
auto_ptr<Thing> q = p;

if (p) p->DoSomething(); // OK: checks p, does nothing
if (q) q->DoSomething(); // OK: checks q, calls function

p.reset(); // does nothing

if (p) p->DoSomething(); // OK: checks p, does nothing
if (q) q->DoSomething(); // OK: checks q, calls function

q.reset(); // deletes the object

if (p) p->DoSomething(); // OK: checks p, does nothing
if (q) q->DoSomething(); // OK: checks q, does nothing

答案 1 :(得分:3)

使用auto_ptr,您可以专门测试NULL以确保指针实际指向某个东西。通过复制构造函数和operator=方法复制指针值的所有权可确保如果指针的所有权被“移动”,则指针实际上将为NULL。最后,当auto_ptr超出范围时,如果内部指针未设置为NULL(即,所有权尚未放弃),它将为其拥有的指针释放内存。

另一方面,使用裸指针,您无法确定指针是悬空还是“拥有”指针,除非您务必确保在删除后将指针设置为NULL等等...但手动执行此操作并非异常安全。另一方面,auto_ptr的接口使指针的“所有权”显式化,并使动态内存分配异常安全。

答案 2 :(得分:3)

首先,它会阻止您的代码编译。声明delete p无效,因为您无法删除auto_ptr。将地址存储在智能指针中时,您不应再在其上调用delete;任何对delete的调用都会立即成为仔细检查代码的原因 - 它只是看起来不对

删除delete语句后,您很快就会遇到运行时错误。在使用q初始化p后,p包含空指针。因此,p->DoSomething()在空指针上调用该方法,并且 应该比原始代码更快地导致崩溃,在原始代码中,您在一个陈旧的无效指针上调用方法。 (对空指针调用方法会导致未定义的行为。典型的结果是崩溃,例如访问冲突或分段错误。无效指针上的调用方法也是未定义的,但通常会导致更微妙的错误,例如丢弃的数据或错误的计算,而不是崩溃。)

答案 3 :(得分:2)

首先,该示例是错误的,因为它在删除p后调用p->DoSomething()。其次,当使用auto_ptr时,你不会直接调用delete,这是由auto_ptr的析构函数处理的。第三,auto_ptr的意思是它不允许指针的多个副本,所以不可能有一个悬空指针。空指针异常优于悬空指针,因为行为已定义。

答案 4 :(得分:1)

使用shared_ptr,您永远不会手动删除它正在管理的内存;当最后一次引用超出范围时,它会自动删除。这使得悬挂指针几乎不可能,除非你手动reset()它。