智能指针什么时候好用?如果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_ptr
或std::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
一行的内容。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;