在这种情况下,为什么我要使用智能指针?

时间:2015-05-04 13:38:31

标签: c++ pointers smart-pointers

我从未使用任何类型的智能指针,但是当主题是指针时,我几乎无处不在地阅读它们。我知道有些情况下智能指针比原始指针更好用,因为在某种程度上它们可以管理指针的所有权。但是,我仍然不知道,&#34之间的界限在哪里?我不需要智能指针"和#34;这是智能指针的情况"。

让我们说,我有以下情况:

class A {
public:
    double get1(){return 1;}
    double get2(){return 2;}
};
class SomeUtilityClass {
public:
    SomeUtilityClass(A* a) : a(a) {}
    double getResult(){return a->get1() + a->get2();}
    void setA(A* a){a = a;}
private:
    A* a;
};
int main(int argc, char** argv) {
    A a;
    SomeUtilityClass u(&a);
    std::cout << u.getResult() << std::endl;
    A a2;
    u.setA(&a2);
    std::cout << u.getResult() << std::endl;
    return 0;
}

这当然是一个过于简单的例子。我的意思是SomeUtilityClass不应该&#34;拥有&#34; A的实例(因为它只是一个实用程序类),因此它只保存一个指针。

关于指针,我所知道的唯一可能出错的是:

  • SomeUtilityClass可以使用空指针
  • 进行实例化
  • 指向的对象可能会被删除/超出范围,而SomeUtilityClass没有注意到它

智能指针如何帮助避免此问题?在这种情况下使用智能指针可以获得哪些其他好处?

PS:我知道智能指针有几个问题(例如this one)。但是,如果您能告诉我有关此特定示例的影响,我将不胜感激。

4 个答案:

答案 0 :(得分:2)

这取决于参数的创建和存储方式。如果您不拥有内存并且可以静态或动态分配,则原始指针是一个非常合理的解决方案 - 特别是如果您需要支持交换数据,如示例中所示。另一个选择是使用std::reference_wrapper,这将解决您的nullptr问题,同时保持相同的语义。

如果您持有指向某个共享资源的指针(即存储在std::shared_ptr某处)并希望能够检查它是否已被删除,则可以保留std::weak_ptr

答案 1 :(得分:1)

如果SomeUtilityClass不拥有成员变量a,则智能指针没有意义。

您可以考虑一个引用成员,它将删除空指针的问题。

答案 2 :(得分:1)

在C ++中表达非拥有指针的默认方式是weak_ptr。要使用weak_ptr,您需要使用shared_ptr获取所有权,因此在您的示例中,您将使用

shared_ptr<A> owner(...)

而不是

A a

然后作为SomeUtilityClass的私有指针成员使用弱指针:

weak_ptr<A> w;

并使用shared_ptr初始化它:

SomeUtilityClass(shared_ptr<A> o) : w(o) {}

但是,您无法直接使用weak_ptr,因为shared_ptr可能会超出范围而您的弱指针不再指向任何内容。使用前你需要锁定它:

shared_ptr<A> locked = w.lock();

如果拥有指针不再管理对象,则locked指针将为空,例如它超出了范围。如果它不是空的,你可以使用它然后它将超出范围自动释放锁定对象。

{+ 1}}和shared_ptr在C ++ 11的标准库中都可用,在Boost中可用于较旧的编译器。

答案 3 :(得分:0)

有不同类型的智能指针。在你的情况下,显然不需要智能指针,但它仍然可以提供一些好处。

  

可以使用空指针

实例化SomeUtilityClass

当你得到一个NULL指针作为参数时,最好通过检查构造函数,抛出异常或以其他方式指示错误来解决这个问题。我很难想象智能指针如何帮助,除非你使用一个不接受NULL的特定智能指针类,所以它已经为你做了检查。

  

指向的对象可能被删除/超出范围,没有   SomeUtilityClass注意到它

实际上可以使用特殊类型的智能指针来解析这个,但是需要指向的对象以某种方式支持销毁通知。一个这样的例子是Qt库中的QPointer类,它只能指向QObject个实例,它们在删除时会通知它,因此当删除对象时,智能指针会自动变为NULL。但是,这种方法存在一些问题:

  1. 每次通过智能指针访问对象时都需要检查NULL。
  2. 如果智能指针指向某个类的实例,例如MyClass扩展执行删除通知的类(Qt案例中为QObject),则会得到奇怪的结果:它是QObject的析构函数,通知智能指针,所以当MyClass析构函数已经开始它的脏工作时你有可能访问它,所以对象被部分破坏,但是指针尚未归零,因为破坏仍在进行中。