为什么要用智能笔呢?



智能指针什么时候好用?如果c++中不鼓励使用指针,为什么还要使用智能指针呢?例如:

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

当你需要维护一个对象的所有权时,智能指针是很好的选择。使用它们将确保适当的破坏。当指针被视为引用时,使用智能指针有时会使更差(例如,在性能方面)。

指针是c++的一个重要组成部分,但在c++ 11中,随着move语义的引入,使用它们变得更加容易(这实际上使unique_ptr成为可能)。这就是为什么在现代代码中,如果可用,您应该始终使用std::unique_ptrstd::shared_ptr


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

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>和普通成员。

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

快速回答:智能指针非常有用(特别是)

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

执行RAII

指针带来的一个问题是(在许多方面,有些是明显的,有些是扭曲的)你的程序崩溃,你要为它们下面的内存负责。这意味着当您动态分配内存(通过new)时,您要对这些内存负责,并且一定不要忘记调用delete。这意味着它会发生,更糟糕的是,在某些情况下,即使您没有忘记,也永远不会到达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利用了这样一个优点:当局部变量超出作用域时,将调用它的dr。

管理指针所有权

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

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

注释-多态性的小解释

需要指针来使用多态性。如果您有一个抽象类MyAbstract(这意味着,它至少有一个虚拟,比如doVirtual()),它就不能被实例化。以下代码:

MyAbstract var;

不会编译,您将从编译器获得Can't instantiate abstract class一行的内容。

但这是合法的(ImplAImplB都从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;

相关内容

  • 没有找到相关文章

最新更新