C++标准库学习笔记(Shared Pointer)-3
2015-06-16 22:59
519 查看
声明:这个博文所有内容均来自于C++标准库-自学教程与参考手册(第二版)英文版 上册。如果转载,务必附带本声明,并注明出处。
smart pointer就是智能指针,它能够自动计数引用,并在最后一次引用后释放,包含于< memory>头文件。C++标准库-自学教程与参考手册(第二版)英文版Page76指出:
Since C, we know that pointers are important but are a source of trouble. One reason to use pointers is to have reference semantics outside the usual boundaries of scope. However, it can be very tricky to ensure that their lifetime and the lifetime of the objects they refer to match, especially when multiple pointers refer to the same object. For example, to have the same object in multiple collections (see Chapter 7), you have to pass a pointer into each collection, and ideally there should be no
problems when one of the pointers gets destroyed (no “dangling pointers” or multiple deletions of the referenced object) and when the last reference to an object gets destroyed (no “resource leaks”).
A usual approach to avoid these kinds of problems is to use “smart pointers.” They are “smart”in the sense that they support programmers in avoiding problems such as those just described. For example, a smart pointer can be so smart that it “knows” whether it is the last pointer to an object and uses this knowledge to delete an associated object only when it, as “last owner” of an object, gets destroyed. Note, however, that it is not sufficient to provide only one smart pointer class. Smart pointers can be smart about different aspects and might fulfill different priorities, because you might pay a price for the smartness. Note that with a specific smart pointer, it’s still possible to misuse a pointer or to program erroneous behavior.
自从C++11以后,C++标准库提供两种类型的 smart pointer: 一个是shared_ptr. 它使得多个smart pointer可以指向同一个object. 另一个是unique_ptr。 它是一种互斥的指针,使得一个object仅有一个smart pointer可以指向它。
查阅C++ reference后,里面也给出了一个利用lambda显示释放的例子。不过我希望调用函数来释放,怎么办?
可见,用函数和用lambda都是可以的。
这里推荐一个网页运行C++的网站:http://cpp.sh/
C++标准库一书中指出,当使用shared_ptr指向一个数组时,需要自己写释放函数(尽量用lambda 吧),虽然不自己写也不一定报错,但是实际是错误的。
shared_ptr是不能直接索引下标的,它并没有重载这个符号,如果你一定要这么索引,那只能自己重载了。
如果不想搞这么麻烦,可以使用 p.get()[index]或者(&*p)[index],参考这里。
——————————————————补充———————————————————
shared pointer 的误用
第一个误用就是循环引用的问题了。循环引用会导致资源得不到释放。
第二个就是多个 shared_ptr 指向一个对象,这样可能导致第一个shared_ptr释放对象后,剩下的都找不到对象而造成错误。
比如:
所以,不能直接将两个shared_ptr直接指向一个对象,而应该这么做:
这样就没问题了,两个 shared_ptr形成了一个group。
这个例子的问题在于使用this作为shared_ptr,这是不可以的。
而应该采用如下方式:
注意shared_from_this()是不能在构造器里面使用的,会导致一个runtime error,因为shared_ptr把自己存放在Person基类的私有成员里面了。
smart pointer就是智能指针,它能够自动计数引用,并在最后一次引用后释放,包含于< memory>头文件。C++标准库-自学教程与参考手册(第二版)英文版Page76指出:
Since C, we know that pointers are important but are a source of trouble. One reason to use pointers is to have reference semantics outside the usual boundaries of scope. However, it can be very tricky to ensure that their lifetime and the lifetime of the objects they refer to match, especially when multiple pointers refer to the same object. For example, to have the same object in multiple collections (see Chapter 7), you have to pass a pointer into each collection, and ideally there should be no
problems when one of the pointers gets destroyed (no “dangling pointers” or multiple deletions of the referenced object) and when the last reference to an object gets destroyed (no “resource leaks”).
A usual approach to avoid these kinds of problems is to use “smart pointers.” They are “smart”in the sense that they support programmers in avoiding problems such as those just described. For example, a smart pointer can be so smart that it “knows” whether it is the last pointer to an object and uses this knowledge to delete an associated object only when it, as “last owner” of an object, gets destroyed. Note, however, that it is not sufficient to provide only one smart pointer class. Smart pointers can be smart about different aspects and might fulfill different priorities, because you might pay a price for the smartness. Note that with a specific smart pointer, it’s still possible to misuse a pointer or to program erroneous behavior.
自从C++11以后,C++标准库提供两种类型的 smart pointer: 一个是shared_ptr. 它使得多个smart pointer可以指向同一个object. 另一个是unique_ptr。 它是一种互斥的指针,使得一个object仅有一个smart pointer可以指向它。
include <iostream> #include <string> #include <vector> #include <memory> using namespace std; int main() { // two shared pointers representing two persons by their name shared_ptr<string> pNico(new string("nico")); //这里使用了隐式转换,将普通 string 指针转换为了shared_ptr<string> shared_ptr<string> pJutta(new string("jutta")); // capitalize person names (*pNico)[0] = 'N'; pJutta->replace(0, 1, "J"); // put them multiple times in a container vector<shared_ptr<string>> whoMadeCoffee; whoMadeCoffee.push_back(pJutta); whoMadeCoffee.push_back(pJutta); whoMadeCoffee.push_back(pNico); whoMadeCoffee.push_back(pJutta); whoMadeCoffee.push_back(pNico); // print all elements for (auto ptr : whoMadeCoffee) { cout << *ptr << " "; } cout << endl; // overwrite a name again *pNico = "Nicolai"; // print all elements again for (auto ptr : whoMadeCoffee) { cout << *ptr << " "; } cout << endl; // print some internal data cout << "use_count: " << whoMadeCoffee[0].use_count() << endl; cout << typeid(pJutta).name() << endl; cout << pJutta << endl; cout << *pJutta << endl; shared_ptr<string> mSharedPtr; mSharedPtr = static_cast<shared_ptr<string> > (new string("Hello world")); //这里使用了static_cast施行转换了 cout << *mSharedPtr << endl; mSharedPtr.reset(new string("Hello world's change")); cout << *mSharedPtr << endl; shared_ptr<string> mSharedPtr2 = make_shared<string>("您好,这里放的是密码。"); cout << *mSharedPtr2 << endl; shared_ptr<string> mSharedPtr3(new string("my shared pointer 3th"), [](string*p){ cout << "delete " << *p << endl; delete p; }); cout << "Now set mSharedPtr3 as nullptr" << endl; mSharedPtr3 = nullptr; cout << "Now call resize of whoMadeCoffee" << endl; whoMadeCoffee.resize(2); //可以看到,这里的mSharedPtr3所指向的对象在它指向别的地方时释放了,而且释放的时候调用了自定义的释放函数,其实是一个lambda表达式 shared_ptr<string> mSharedPtr4(new string("my shared pointer 3th")); return 0; }
查阅C++ reference后,里面也给出了一个利用lambda显示释放的例子。不过我希望调用函数来释放,怎么办?
// shared_ptr destructor example #include <iostream> #include <memory> void deleter2(int * p) { std::cout << "Now delete shared_ptr in function " << *p << std::endl; delete p; } int main () { auto deleter = [](int*p){ std::cout << "[deleter called]\n"; delete p; }; std::shared_ptr<int> foo (new int,deleter); std::shared_ptr<int> foo2 (new int,deleter2); std::cout << "use_count: " << foo.use_count() << '\n'; return 0; // [deleter called] }
可见,用函数和用lambda都是可以的。
这里推荐一个网页运行C++的网站:http://cpp.sh/
C++标准库一书中指出,当使用shared_ptr指向一个数组时,需要自己写释放函数(尽量用lambda 吧),虽然不自己写也不一定报错,但是实际是错误的。
std::shared_ptr<int> p(new int[10], [](int* p) { delete[] p; });
shared_ptr是不能直接索引下标的,它并没有重载这个符号,如果你一定要这么索引,那只能自己重载了。
T& operator[] (int idx) { return ptr_.get()[idx]; };
如果不想搞这么麻烦,可以使用 p.get()[index]或者(&*p)[index],参考这里。
——————————————————补充———————————————————
shared pointer 的误用
第一个误用就是循环引用的问题了。循环引用会导致资源得不到释放。
第二个就是多个 shared_ptr 指向一个对象,这样可能导致第一个shared_ptr释放对象后,剩下的都找不到对象而造成错误。
比如:
int* p = new int{}; shared_ptr<int> sp1(p); shared_ptr<int> sp2(p);//错误!
所以,不能直接将两个shared_ptr直接指向一个对象,而应该这么做:
int* p = new int{}; shared_ptr<int> sp1(p); shared_ptr<int> sp2(sp1); //OK
这样就没问题了,两个 shared_ptr形成了一个group。
/* The following code example is taken from the book * "The C++ Standard Library - A Tutorial and Reference, 2nd Edition" * by Nicolai M. Josuttis, Addison-Wesley, 2012 * * (C) Copyright Nicolai M. Josuttis 2012. * Permission to copy, use, modify, sell and distribute this software * is granted provided this copyright notice appears in all copies. * This software is provided "as is" without express or implied * warranty, and with no claim as to its suitability for any purpose. */ #include <iostream> #include <string> #include <vector> #include <memory> using namespace std; class Person { public: string name; shared_ptr<Person> mother; shared_ptr<Person> father; vector<weak_ptr<Person>> kids; // weak pointer !!! Person (const string& n) : name(n) { } void setParentsAndTheirKids (shared_ptr<Person> m = nullptr, shared_ptr<Person> f = nullptr) { mother = m; father = f; if (m != nullptr) { m->kids.push_back(shared_ptr<Person>(this)); } if (f != nullptr) { f->kids.push_back(shared_ptr<Person>(this)); } } ~Person() { cout << "delete " << name << endl; } }; shared_ptr<Person> initFamily (const string& name) { shared_ptr<Person> mom(new Person(name+"'s mom")); shared_ptr<Person> dad(new Person(name+"'s dad")); shared_ptr<Person> kid(new Person(name)); kid->setParentsAndTheirKids(mom,dad); return kid; } int main() { shared_ptr<Person> p = initFamily("nico"); cout << "nico's family exists" << endl; cout << "- nico is shared " << p.use_count() << " times" << endl; cout << "- name of 1st kid of nico's mom: " << p->mother->kids[0].lock()->name << endl; p = initFamily("jim"); cout << "jim's family exists" << endl; }
这个例子的问题在于使用this作为shared_ptr,这是不可以的。
而应该采用如下方式:
/* The following code example is taken from the book * "The C++ Standard Library - A Tutorial and Reference, 2nd Edition" * by Nicolai M. Josuttis, Addison-Wesley, 2012 * * (C) Copyright Nicolai M. Josuttis 2012. * Permission to copy, use, modify, sell and distribute this software * is granted provided this copyright notice appears in all copies. * This software is provided "as is" without express or implied * warranty, and with no claim as to its suitability for any purpose. */ #include <iostream> #include <string> #include <vector> #include <memory> using namespace std; class Person : public enable_shared_from_this<Person> { public: string name; shared_ptr<Person> mother; shared_ptr<Person> father; vector<weak_ptr<Person>> kids; // weak pointer !!! Person (const string& n) : name(n) { } void setParentsAndTheirKids (shared_ptr<Person> m = nullptr, shared_ptr<Person> f = nullptr) { mother = m; father = f; if (m != nullptr) { m->kids.push_back(shared_from_this()); } if (f != nullptr) { f->kids.push_back(shared_from_this()); } } ~Person() { cout << "delete " << name << endl; } }; shared_ptr<Person> initFamily (const string& name) { shared_ptr<Person> mom(new Person(name+"'s mom")); shared_ptr<Person> dad(new Person(name+"'s dad")); shared_ptr<Person> kid(new Person(name)); kid->setParentsAndTheirKids(mom,dad); return kid; } int main() { shared_ptr<Person> p = initFamily("nico"); cout << "nico's family exists" << endl; cout << "- nico is shared " << p.use_count() << " times" << endl; cout << "- name of 1st kid of nico's mom: " << p->mother->kids[0].lock()->name << endl; p = initFamily("jim"); cout << "jim's family exists" << endl; }
注意shared_from_this()是不能在构造器里面使用的,会导致一个runtime error,因为shared_ptr把自己存放在Person基类的私有成员里面了。
相关文章推荐
- eclipse安装C/C++插件cdt
- Effective C++条款05解读: 了解C++默默编写并调用哪些函数
- 求众数(c语言)
- C语言-判断闰年
- C++中static、const、static const修饰变量作用详解(转)
- PCA人脸识别学习及C语言实现
- [C/CPP系列知识] Type difference of character literals 和 bool in C and C++
- C++中重载/覆盖/隐藏的区别
- C语言笔记之指针的初步认识
- C++下高效率int转成string
- 开始学习C++心得实例(4)
- c++异常处理机制
- 【leetcode c++】19 removeNthFromEnd
- c++容器之vector
- [C/CPP系列知识] C++中extern “C” name mangling -- Name Mangling and extern “C” in C++
- C++ Virtual介绍
- C++ Virtual介绍 分类: C/C++ 2015-06-16 21:36 26人阅读 评论(0) 收藏
- FreeGLUT Tips: Resolve compile error C2664: cannot convert argument 2 from '_TCHAR *[]' to 'char **'
- C语言和Fortran语言的差异
- 迷宫的最短路径 代码(C++)