您的位置:首页 > 编程语言 > C语言/C++

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

2016-06-09 01:13 666 查看

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_shared
move
两个函数可以用于operator=操作。



/*
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;
}




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

虽然使用智能指针仍然要考虑引用计数的问题,但还是应该承认使用智能指针确实比使用原生态的指针方便太多,特别是在erase元素的时候。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: