[C++]Shared_ptr使用详解&&实现链表

Shared_ptr使用详解

在之前参加项目时,有一条准则为不使用原生态指针,而使用智能指针。那么我将在本文中介绍shard_ptr的内容。本文分两个部分组成,第一部分是讲解shard_ptr的使用方法,(至于智能指针的理解,此处不赘述)以及第二部分使用shared_ptr实现链表的部分功能,(其他功能也是类似的而已)。

(知识点摘自cplusplus)

构造部分

构造函数有4个参数分别有以下含义:

#include <algorithm>
#include <iostream>
#include <memory>
using namespace std;
/* default (1) constexpr shared_ptr() noexcept; from null pointer (2) constexpr shared_ptr(nullptr_t) : shared_ptr() {} from pointer (3) template <class U> explicit shared_ptr (U* p); with deleter (4) template <class U, class D> shared_ptr (U* p, D del); template <class D> shared_ptr (nullptr_t p, D del); with allocator (5) template <class U, class D, class Alloc> shared_ptr (U* p, D del, Alloc alloc); template <class D, class Alloc> shared_ptr (nullptr_t p, D del, Alloc alloc); copy (6) shared_ptr (const shared_ptr& x) noexcept; template <class U> shared_ptr (const shared_ptr<U>& x) noexcept; copy from weak (7) template <class U> explicit shared_ptr (const weak_ptr<U>& x); move (8) shared_ptr (shared_ptr&& x) noexcept; template <class U> shared_ptr (shared_ptr<U>&& x) noexcept; move from managed (9) template <class U> shared_ptr (auto_ptr<U>&& x); template <class U, class D> shared_ptr (unique_ptr<U,D>&& x); aliasing (10) template <class U> shared_ptr (const shared_ptr<U>& x, element_type* p) noexcept; */
struct C {
  int* data;
};

int main() {
  std::shared_ptr<int> p1;
  std::shared_ptr<int> p2(nullptr);
  std::shared_ptr<int> p3(new int);
  std::shared_ptr<int> p4(new int, std::default_delete<int>());
  std::shared_ptr<int> p5(new int, [](int* p) { delete p; },
                          std::allocator<int>());
  std::shared_ptr<int> p6(p5);
  std::shared_ptr<int> p7(std::move(p6));
  std::shared_ptr<int> p8(std::unique_ptr<int>(new int));
  std::shared_ptr<C> obj(new C);
  std::shared_ptr<int> p9(obj, obj->data);

  std::cout << "use_count:\n";
  std::cout << "p1: " << p1.use_count() << '\n';
  std::cout << "p2: " << p2.use_count() << '\n';
  std::cout << "p3: " << p3.use_count() << '\n';
  std::cout << "p4: " << p4.use_count() << '\n';
  std::cout << "p5: " << p5.use_count() << '\n';
  std::cout << "p6: " << p6.use_count() << '\n';
  std::cout << "p7: " << p7.use_count() << '\n';
  std::cout << "p8: " << p8.use_count() << '\n';
  std::cout << "p9: " << p9.use_count() << '\n';
  return 0;
}

operator=

make_sharedmove两个函数可以用于operator=操作。
[C++]Shared_ptr使用详解&&实现链表_第1张图片

/* copy (1) shared_ptr& operator= (const shared_ptr& x) noexcept; template <class U> shared_ptr& operator= (const shared_ptr<U>& x) noexcept; move (2) shared_ptr& operator= (shared_ptr&& x) noexcept; template <class U> shared_ptr& operator= (shared_ptr<U>&& x) noexcept; move from (3) template <class U> shared_ptr& operator= (auto_ptr<U>&& x); template <class U, class D> shared_ptr& operator= (unique_ptr<U,D>&& x); */
#include <iostream>
#include <memory>
int main() {
  std::shared_ptr<int> foo;
  std::shared_ptr<int> bar(new int(10));

  foo = bar;  // copy

  bar = std::make_shared<int>(20);  // move

  std::unique_ptr<int> unique(new int(30));
  foo = std::move(unique);  // move from unique_ptr

  std::cout << "*foo: " << *foo << '\n';
  std::cout << "*bar: " << *bar << '\n';
  return 0;
}

reset操作

回收内存并且改变内存。

/* void reset() noexcept; template <class U> void reset (U* p); template <class U, class D> void reset (U* p, D del); template <class U, class D, class Alloc> void reset (U* p, D del, Alloc alloc); */
#include <iostream>
#include <memory>
int main() {
  std::shared_ptr<int> sp;  // empty

  sp.reset(new int);  // takes ownership of pointer
  *sp = 10;
  std::cout << *sp << '\n';

  sp.reset(new int);  // deletes managed object, acquires new pointer
  *sp = 20;
  std::cout << *sp << '\n';

  sp.reset();  // deletes managed object
  return 0;
}

make_share

构造内存。

/* template <class T, class... Args> shared_ptr<T> make_shared (Args&&... args); */
#include <iostream>
#include <memory>
int main() {
  std::shared_ptr<int> foo = std::make_shared<int>(10);
  // same as:
  std::shared_ptr<int> foo2(new int(10));

  auto bar = std::make_shared<int>(20);

  auto baz = std::make_shared<std::pair<int, int>>(30, 40);

  std::cout << "*foo: " << *foo << '\n';
  std::cout << "*bar: " << *bar << '\n';
  std::cout << "*baz: " << baz->first << ' ' << baz->second << '\n';

  return 0;
}

allocate_shared

/* template <class T, class Alloc, class... Args> shared_ptr<T> allocate_shared (const Alloc& alloc, Args&&... args); */
#include <iostream>
#include <memory>

int main () {
  std::allocator<int> alloc;    // the default allocator for int
  std::default_delete<int> del; // the default deleter for int

  std::shared_ptr<int> foo = std::allocate_shared<int> (alloc,10);

  auto bar = std::allocate_shared<int> (alloc,20);

  auto baz = std::allocate_shared<std::pair<int,int>> (alloc,30,40);

  std::cout << "*foo: " << *foo << '\n';
  std::cout << "*bar: " << *bar << '\n';
  std::cout << "*baz: " << baz->first << ' ' << baz->second << '\n';

  return 0;
}

shared_ptr实现链表

#include <iostream>
#include <memory>
using namespace std;
template <typename T>
struct node {
  T value;
  shared_ptr<node> next;
  node(T val = 0, shared_ptr<node> n = nullptr) : value(val), next(n) {}
};

template <typename T>
class list {
private:
  typedef shared_ptr<node<T>> pointer;
  typedef T value_type;

private:
  pointer head;
  size_t size;
public:
  list() : head(make_shared<node<T>>()), size(0) {}
  ~list() {}
  void push_back(const value_type& val) {
    pointer temp = head;
    if (temp.get()->next != nullptr) {
      temp = temp.get()->next;
    }
    auto temps = make_shared<node<T>>(val);
    (*temp.get()).next = temps;
    size++;
  }
  void push_front(const value_type& val) {
    pointer temp = make_shared<node<T>>(0, head);
    head.get()->value = val;
    head = temp;
    size++;
  }
  bool insert(int pos, const value_type& val) {
    if (pos == 0) {
      push_front(val);
      return true;
    }
    if (pos == size - 1) {
      push_back(val);
      return true;
    }
    if (pos > size) {
      return false;
    } else {
      pointer temp = head.get()->next;
      for (int i = 0; i != pos; i++) {
        temp = temp.get()->next;
      }
      pointer add = make_shared<node<T>>(val, nullptr);
      temp.get()->next = add;
      size++;
      return true;
    }
  }
  bool erase(int pos) {
    if (pos == 0) {
      head = head.get()->next;
      size--;
      return true;
    }
    if (pos >= size) {
      return false;
    } else {
      pointer del = head.get()->next;
      for (int i = 0; i != pos - 1; i++) {
        del = del.get()->next;
      }
      del.get()->next = del.get()->next->next;
      size--;
      return true;
    }
  }
  friend ostream& operator<<(ostream& out, list<T> & orig) {
    pointer temp = orig.head.get()->next;
    while (temp.get()->next != nullptr) {
      out << temp.get()->value << " ";
      temp = temp.get()->next;
    }
    out << temp.get()->value << endl;
    return out;
  }
};
int main() {
  list<int> li;
  li.push_back(10);
  li.push_back(123);
  li.push_front(12);
  li.insert(0, 20);
  li.erase(2);
  cout << li;
  return 0;
}

[C++]Shared_ptr使用详解&&实现链表_第2张图片

这个shared_ptr的链表实现版本比我想象中要出现更多的问题,最主要的问题是我夸大了shared_ptr的内存管理能力。一开始我以为shared_ptr的对象只要到达使用析构函数的部分,不管他的引用计数为多少都会被回收资源(因为他们不会再被使用)。但实际情况并不是如此,并没有这么智能!到达析构函数时,如果引用计数大于1,那么他们只会调用-1的操作,并不会直接忽略引用计数而直接析构资源。(细想一下,确实应当如此。)基于最初的妄想,我设计了一个双头链表(有nextprev对象),最后出现了大量的内存泄露。最后我把node设计为单向链表,然后就没有内存泄露了。

虽然使用智能指针仍然要考虑引用计数的问题,但还是应该承认使用智能指针确实比使用原生态的指针方便太多,特别是在erase元素的时候。

你可能感兴趣的:([C++]Shared_ptr使用详解&&实现链表)