banner
Matrix

Matrix

Abyss
email
github

Petty C++ 指针

智能指针#

C++ 中的智能指针是一种用于管理动态分配的对象的指针。它们提供了自动内存管理,可以帮助避免内存泄漏和悬空指针的问题。C++ 标准库提供了两种主要的智能指针:std::unique_ptrstd::shared_ptr

  1. std::unique_ptr
    std::unique_ptr是一种独占所有权的智能指针。它确保只有一个指针可以访问给定的资源。当std::unique_ptr超出范围或被删除时,它会自动释放所管理的对象。它不能被复制,但可以通过移动语义传递所有权。使用std::make_unique函数可以方便地创建std::unique_ptr对象。
{
  std::unique_ptr<int> ptr = std::make_uniqure<int>(42);
  std::cout << *ptr << std::endl;
}

// ptr 超出范围后,其管理的对象会被自动释放
  1. std::shared_ptr
    std::shared_ptr是一种共享所有权的智能指针。它可以被多个指针共享,并且会跟踪有多少个指针引用了给定的资源。只有当最后一个std::shared_ptr超出范围或被删除时,才会释放所管理的对象。它可以通过复制来共享所有权,也可以通过移动语义传递所有权。使用std::make_shared函数可以方便地创建std::shared_ptr对象。

{
std::unique_ptr ptr1 = std::make_uniqure(42);
std::unique_ptr ptr2 = ptr1; // 共享所有权
}

//ptr1 和 ptr2 超出范围后,其管理的对象会被自动释放

智能指针的使用可以有效地管理动态分配的对象,避免内存泄漏和悬空指针的问题。但需要注意,智能指针并不能解决所有的内存管理问题,例如循环引用可能导致资源无法释放。因此,在使用智能指针时,仍然需要谨慎设计和管理对象的生命周期。

关于共享指针, 以 std::make_shared<Chunk>(position) 为例#

std::make_shared<Chunk>(position) 是一个使用 std::make_shared 函数创建 Chunk 对象的语法。

具体来说,这行代码使用了尖括号 <Chunk> 来指定模板参数,告诉 std::make_shared 函数我们要创建的对象的类型是 Chunk。然后,括号中的 position 是传递给 Chunk 构造函数的参数。

std::make_shared 是一个模板函数,它的定义如下:

template<typenameT, typename... Args>
shared_ptr<T> make_shared(Args&&... args);

它接受一个可变数量的参数 Args&&... args,这些参数将被传递给 T 类型的构造函数来创建对象。在这个例子中,TChunk 类型,Argsposition 的类型。

std::make_shared 函数返回一个 shared_ptr<T> 类型的共享指针,它指向通过传递的参数构造的 T 类型对象。

因此,std::make_shared<Chunk>(position) 这行代码的作用是创建一个 Chunk 类型的对象,并使用共享指针来管理该对象的生命周期。同时,将 position 作为参数传递给 Chunk 的构造函数,以便在创建对象时进行初始化。

实际上,std::make_shared 主要用于构造新的对象。它会在堆上动态分配内存,并使用传递的参数来调用对象的构造函数

如果有一个已经存在的实例,并且想要将其包装在一个共享指针中进行管理,可以使用 std::shared_ptr 的构造函数或 std::make_shared 的变体来实现。

使用 std::shared_ptr 的构造函数可以将一个已经存在的指针包装成共享指针。#

例如:

Chunk* existingChunk = newChunk(position);
std::shared_ptr<Chunk> sharedChunk(existingChunk);

在这个例子中,existingChunk 是一个已经存在的 Chunk 对象的指针,通过将它传递给 std::shared_ptr 构造函数,可以创建一个共享指针 sharedChunk 来管理该对象的生命周期。

在这种情况下,不应该继续使用 existingChunk,因为一旦 sharedChunk 被销毁(或者最后一个拥有它的共享指针被销毁),它指向的内存会被自动释放。如果在那之后尝试访问 existingChunk,将会导致未定义行为,比如访问已经释放的内存。

不推荐的!

另一种方法是使用 std::make_shared 的变体,即 std::allocate_shared

Chunk* existingChunk = newChunk(position);
std::shared_ptr<Chunk> sharedChunk = std::allocate_shared<Chunk>(std::allocator<Chunk>(), *existingChunk);

在这个例子中,使用 std::allocate_shared<Chunk>(std::allocator<Chunk>(), *existingChunk) 会创建一个新的 Chunk 实例,并且这个新实例是通过复制 existingChunk 指向的对象来初始化的。这里并没有发生将普通指针 existingChunk 转换为共享指针的行为,而是发生了对象的复制。std::allocate_shared 使用提供的对象(即 *existingChunk)作为复制构造函数的参数来创建新对象,并由返回的共享指针管理。

通过 std::allocate_shared 创建一个对象的副本并同时保留原始指针指向的对象 —— 通常是不推荐的行为。这种做法会导致以下几个问题:

  1. 内存管理复杂化:这种方法创建了两个独立的对象实例,一个由原始指针管理,另一个由共享指针管理。这就需要你分别管理这两个对象的生命周期,增加了内存泄漏的风险。

  2. 设计意图不明确:智能指针(如 std::shared_ptr)的引入主要是为了简化内存管理,通过自动管理对象的生命周期来减少内存泄漏和悬垂指针的风险。通过复制对象而不是接管原始指针,你实际上没有利用智能指针的主要优势。

  3. 性能开销:复制对象可能涉及显著的性能开销,尤其是当对象较大或复制操作代价高昂时。如果没有必要创建对象的副本,这种开销是可以避免的。

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。