特别是智能指针好用,如果不鼓励使用C ++中的指针,为什么还要使用智能指针呢?举个例子:
class Object { }
smart_pointer < Object > pInstance;
//wherein I can use the very simple way
Object instance;
答案 0 :(得分:5)
当您需要维护对象的所有权时,智能指针很好。使用它们将确保适当的破坏。当指针被视为参考时,使用智能指针有时会更糟(例如,在性能方面)。
指针是C ++的重要组成部分,但使用它们变得更加容易,因为C ++ 11中的智能引入了移动语义(基本上使unique_ptr
成为可能)。这就是为什么在现代代码中,如果可用,您应该始终使用std::unique_ptr
或std::shared_ptr
。
编辑:你问了一个例子,指针有利于使用。我能想到的最常见的问题是某个系统的可选组件。该组件将使用大量内存,因此您不希望始终分配它,也不要控制其分配(因此它本身不能处于“空”状态,即不可为空)。 Boost.Optional和C ++ 14-ish std::optional
分配TOD的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>
和普通成员。
无论如何,在这种情况下使用智能指针可以让你保持零规则;您不必编写析构函数,复制构造函数或赋值运算符,该类将安全地运行。
答案 1 :(得分:1)
快速回答:智能指针对于(特别是)
非常有用执行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;