-8

什么时候特别适合使用智能指针,如果不鼓励使用 C++ 中的指针,为什么还要使用智能指针?举个例子:

class Object {  }

smart_pointer < Object > pInstance;
//wherein I can use the very simple way
Object instance;
4

2 回答 2

5

当您需要维护对象的所有权时,智能指针非常有用。使用它们将确保适当的销毁。当指针被视为引用时,使用智能指针有时会更糟(例如,在性能方面)。

指针是 C++ 的重要组成部分,但在 C++11 中引入了移动语义(这基本上使之成为unique_ptr可能),使用它们变得更加容易。这就是为什么在现代代码中你应该总是使用std::unique_ptr或者std::shared_ptr如果可用的话。


编辑:你问了一个例子,指针可能有益于使用。我能想到的最常见的问题是某个系统的可选组件。该组件将使用大量内存,因此您不想总是分配它,也不想控制它的分配(因此它本身不能处于“空”状态,即不可为空)。Boost.Optional 和 C++14-ishstd::optional分配 T 的 POD-ish 大小的内存,所以它们不会这样做。使用指针,您可以选择分配该内存:

class Outer { 
    std::unique_ptr<BigInner> optionalComponent;
public:
    void initializeOptionalComponent() { 
        optionalComponent = new BigInner();
    }
    void useOptionalComponent() {
        if (!optionalComponent)
            // handle the error
        // operate
    } 
};

这将解决问题,但会引入另一个明显的问题: optionalComponent 可以为 null,这要求所有使用它的函数始终检查有效状态。如果它是一个普通的按值成员,它将(或至少应该)始终处于有效状态。因此,如果您不需要指针,请不要使用它,使用vector<MyClass>和普通成员。

无论如何,在这种情况下使用智能指针可以让您保持零规则;您不必编写析构函数、复制构造函数或赋值运算符,并且该类将安全地运行。

于 2013-06-12T09:54:43.287 回答
1

快速回答:智能指针对(尤其是)有用

  • 执行RAII
  • 管理指针所有权

执行 RAII

指针带来的一个问题并导致程序中的崩溃(在许多方面,一些明显的,一些扭曲的)是你对它们下面的内存负责。这意味着当您动态分配内存时(通过new),您对这块内存负责,并且一定不要忘记调用delete. 这意味着它会发生,更糟糕的是,即使你没有忘记,删除语句也永远不会到达。考虑这段代码:

void function(){
    MyClass* var = new MyClass;

    //Do something

    delete var;
}

现在,如果这个函数在到达 delete 语句之前抛出异常,指针将不会被删除......内存泄漏!

RAII 是一种避免这种情况的方法:

void function(){
    std::shared_ptr<MyClass> var(new MyClass);

    //Do something

    //No need to delete anything
}

指针由对象持有,并在其析构函数中删除。与前面的代码不同的是,如果函数抛出异常,则会调用共享指针的析构函数,从而删除指针,避免内存泄漏。

RAII 利用了这样一个事实,即当局部变量超出范围时,它的 dtor 会被调用。

管理指针所有权

请注意我在前面的示例中使用了哪个智能指针。这std::shared_ptr是一个智能指针,当您传递指针时很有用。如果您的代码的许多部分需要指向同一个对象的指针,那么决定应该在哪里删除它可能会很棘手。您可能想在某处删除指针,但如果您的代码的另一部分正在使用它怎么办?它会导致访问已删除的指针,这是不可取的!std::shared_ptr有助于防止这种情况。当你传递一个 shared_ptr 时,它会跟踪有多少部分代码引用了它。当不再有对该指针的任何引用时,该指针将删除内存。换句话说,当没有人再使用指针时,它就会被安全地删除

还有其他类型的智能指针可以解决其他问题,例如std::unique_ptr提供一个指针,该指针是其下方指针的唯一所有者。

注意 - 关于多态性的小解释

需要使用多态性的指针。如果你有一个抽象类MyAbstract(也就是说,它至少有一个虚拟类,比如说doVirtual()),它就不能被实例化。以下代码:

MyAbstract var;

不会编译,你会Can't instantiate abstract class从你的编译器中得到类似的东西。

但这是合法的(两者都ImplA公开ImplB继承自MyAbstract

MyAbstract* varA = new ImplA;
MyAbstract* varB = new ImplB;

varA->doVirtual(); //Will call ImplA implementation
varB->doVirtual(); //Will call ImplB implementation

delete varA;
delete varB;
于 2013-06-12T10:44:42.927 回答