unique_ptr 堆和栈分配

unique_ptr heap and stack allocation

原始指针可以指向在堆栈或堆上分配的对象。

堆分配示例:

// heap allocation
int* rawPtr = new int(100);
std::cout << *rawPtr << std::endl;      // 100

堆栈分配示例:

int i = 100;
int* rawPtr = &i;
std::cout << *rawPtr << std::endl;      // 100

堆分配使用 auto_ptr 示例:

int* rawPtr = new int(100);
std::unique_ptr<int> uPtr(rawPtr);
std::cout << *uPtr << std::endl;        // 100

堆栈分配使用 auto_ptr 示例:

int i = 100;
int* rawPtr = &i;
std::unique_ptr<int> uPtr(rawPtr);      // runtime error

'smart pointers' 是否旨在用于指向堆上动态创建的对象?对于 C++11,我们是否应该继续使用原始指针来指向堆栈分配的对象?谢谢。

运行时错误是由于 delete 是在从未分配给 new 的内存位置上调用的。

如果一个对象已经用 dynamic storage duration 创建(通常实现为在 'heap' 上创建),那么 'smart pointer' 将不会正确运行,如运行时错误所示。

Are 'smart pointers' intended to be used to point to dynamically created objects on the heap? For C++11, are we supposed to continue using raw pointers for pointing to stack allocated objects?

至于应该做什么,嗯,考虑一下存储持续时间以及具体是如何创建对象会有所帮助。

  • 如果对象具有自动存储持续时间(堆栈),则避免获取地址并使用引用。所有权不属于指针,引用使所有权更清晰。
  • 如果对象具有动态存储持续时间(堆),那么智能指针是可行的方法,因为它可以管理所有权。

所以对于最后一个例子,以下会更好(指针拥有 int):

auto uPtr = std::make_unique<int>(100);

uPtr 将具有自动存储持续时间,并在超出范围时调用析构函数。 int 将具有动态存储持续时间(堆)并将被智能指针 delete 编辑。

通常可以避免使用 newdelete 并避免使用原始指针。对于 make_uniquemake_shared,不需要 new

Are 'smart pointers' intended to be used to point to dynamically created objects on the heap?

它们用于堆分配的对象以防止泄漏。

C++ 的指导原则是使用指向 refer 的普通指针指向单个对象(但不拥有它)。对象的 owner 按值、在容器中或通过智能指针持有它。

Are 'smart pointers' intended to be used to point to dynamically created objects on the heap?

是的,但这只是默认设置。请注意,std::unique_ptr 有一个 constructor(该页上的编号 (3)/(4)),它采用 you 以某种方式获得的指针,以及一个提供的“删除器”。在这种情况下,唯一指针不会对堆做任何事情(除非你的删除器这样做)。

For C++11, are we supposed to continue using raw pointers for pointing to stack allocated objects? Thank you.

您应该在不“拥有”指针的代码中使用原始指针——不需要关心分配或释放;这与您是指向堆、堆栈还是其他地方无关。

另一个使用它的地方是当你为 protected/private 成员实施一些具有复杂所有权模式的 class 时。

PS:拜托,忘掉std::auto_ptr...假装它不存在:-)

智能指针通常用于指向用new分配并用delete删除的对象。它们不必以这种方式使用,但如果我们想猜测语言结构的预期用途,那似乎就是意图。

您的代码在上一个示例中崩溃的原因是 "deleted with delete" 部分。当它超出范围时,unique_ptr 将尝试 delete 它具有指针的对象。由于它是在堆栈上分配的,因此失败了。就像你写的一样,delete rawPtr;

由于堆对象通常使用智能指针,所以有一个函数可以在堆上分配并一次性转换为智能指针。 std::unique_ptr<int> uPtr = make_unique<int>(100); 将执行第三个示例前两行的操作。还有一个匹配的 make_shared 用于共享指针。

可以对堆栈对象使用智能指针。您所做的是指定智能指针使用的删除器,提供一个不调用 delete 的删除器。因为它是一个堆栈变量,不需要做任何事情来删除它,所以删除器什么也做不了。这让人不禁要问,如果智能指针所做的只是调用一个什么都不做的函数,那么它有什么意义呢?这就是为什么您通常不会看到与堆栈对象一起使用的智能指针。但这里有一个显示一些有用性的示例。

{
    char buf[32];
    auto erase_buf = [](char *p) { memset(p, 0, sizeof(buf)); };
    std::unique_ptr<char, decltype(erase_buf)> passwd(buf, erase_buf);

    get_password(passwd.get());
    check_password(passwd.get());
}
// The deleter will get called since passwd has gone out of scope.
// This will erase the memory in buf so that the password doesn't live
// on the stack any longer than it needs to.  This also works for
// exceptions!  Placing memset() at the end wouldn't catch that.