[c++] Why should I use Smart Pointers
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了[c++] Why should I use Smart Pointers,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5161字,纯文字阅读大概需要8分钟。
内容图文
![[c++] Why should I use Smart Pointers](/upload/InfoBanner/zyjiaocheng/634/f5f821d25d7d4862a680e7d32a940ed6.jpg)
深入理解智能指针
共享指针 - 热身问题
一、学习资源
C++中的智能指针
Ref: https://zhuanlan.zhihu.com/p/71649913
二、销毁
[ 这部分仅关于:shared_ptr ]
vector销毁,vector中的指针们所指向的各自“空间“也需要销毁。
vector的某个指针改变,相联系的指针内容全部改变。
![[c++] Why should I use Smart Pointers - 文章图片](/upload/getfiles/0001/2021/5/1/20210501024351170.jpg)
![[c++] Why should I use Smart Pointers - 文章图片](/upload/getfiles/0001/2021/5/1/20210501024351280.jpg)
// util/sharedptr1.cpp #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")); 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; }View Code
定义销毁行为
如果某个指针要放弃某一块内存时,使用 lambda 作为构造函数的第二个参数,定义销毁操作。
当对象的最后一个指针被调用时,lambda被调用。
shared_ptr<string> pNico(new string("nico"), [](string* p) { cout << "delete " << *p << endl; delete p; } ); ... pNico = nullptr; // pNico does not refer to the string any longer whoMadeCoffee.resize(2); // all copies of the string in pNico are destroyed
处理数组
默认的销毁行为不会执行delete[],所以要自己定义销毁行为,例如:
std::shared_ptr<int> p(new int[10], [](int* p) { delete[] p; // <---- lambda } );
另一种方式也可以:
std::shared_ptr<int> p(new int[10], std::default_delete<int[]>());
清理临时文件
处理清理内存以外,还有其他的资源需要处理,以下是一个清理临时文件的示例:
共享指针,指向 ”输出流“ 这个 ”对象“。
#include <string> #include <fstream> // for ofstream #include <memory> // for shared_ptr #include <cstdio> // for remove()
class FileDeleter { private: std::string filename;
public: FileDeleter (const std::string& fn): filename(fn) {
}
void operator () (std::ofstream* fp) { fp->close(); // close.file std::remove(filename.c_str()); // delete file } };
int main() { // create and open temporary file: std::shared_ptr<std::ofstream> fp( new std::ofstream("tmpfile.txt"), FileDeleter("tmpfile.txt") ); ... }
清理共享内存
shm_unlink主要用于linux Posix模式共享内存中的删除共享内存。
// util/sharedptr3.cpp #include <memory> // for shared_ptr #include <sys/mman.h> // for shared memory #include <fcntl.h> #include <unistd.h> #include <cstring> // for strerror() #include <cerrno> // for errno #include <string> #include <iostream>
class SharedMemoryDetacher { public: void operator () (int* p) { std::cout << "unlink /tmp1234" << std::endl; if (shm_unlink("/tmp1234") != 0) { std::cerr << "OOPS: shm_unlink() failed" << std::endl; } } };
std::shared_ptr<int> getSharedIntMemory(int num) { void* mem;
int shmfd = shm_open("/tmp1234", O_CREAT|O_RDWR, S_IRWXU|S_IRWXG); if (shmfd < 0) { throw std::string(strerror(errno)); } if (ftruncate(shmfd, num*sizeof(int)) == -1) { throw std::string(strerror(errno)); }
mem = mmap(nullptr, num*sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0); if (mem == MAP_FAILED) { throw std::string(strerror(errno)); } return std::shared_ptr<int>(static_cast<int*>(mem), SharedMemoryDetacher()); }
int main() { // get and attach shared memory for 100 ints: std::shared_ptr<int> smp(getSharedIntMemory(100));
// init the shared memory for (int i = 0; i < 100; ++i) { smp.get()[i] = i*42; }
// deal with shared memory somewhere else: ... std::cout << "<return>" << std::endl; std::cin.get();
// release shared memory here: smp.reset(); ... }
析构函数清理
当然还有一种更加清晰的实现方法:构造函数实现初始化,析构函数实现清理。这样就可以简单地使用shared_ptr管理对象。
三、初始化
(1) 为了避免隐式转换,智能指针不能使用赋值的方式初始化,使用括号初始化或者列表初始化是没有问题的。
(2) 另一种初始化的方法是使用make_shared<>,它是一种 更好且更安全 的方法:因为使用new时会创建一个对象,计算它的引用计数时会创建一个对象,而make_shared只会创建一个对象,并且不会出现控制模块失效的情况。
shared_ptr<string> p1 = make_shared<string>(10, '9'); shared_ptr<string> p2 = make_shared<string>("hello"); shared_ptr<string> p3 = make_shared<string>();
(3) 先定义一个智能指针再进行赋值。但是不能使用赋值运算符(=),必须使用reset函数。
shared_ptr<string> pNico4; pNico4 = new string("nico"); // ERROR: no assignment for ordinary pointers pNico4.reset(new string("nico")); // OK
类 weak_ptr
一、shared_ptr 的弊端
使用shared_ptr的主要原因是不想关注资源的释放。但是某些情况下shared_ptr会出现错误或者失效。
1、循环引用问题:如果两个对象使用shared_ptr指向彼此,当释放的时候,将不会自动释放资源,因为引用计数的计算有问题。
2、当共享对象的时候,指针的生命期要长于对象,因此对象不会被shared_ptr删除。指针就无法注意到对象是否释放。
如果一个资源将被多层传递和访问,那么参数类型该用 weak_ptr 还是 shared_ptr?
如何评价 C++11 的右值引用(Rvalue reference)特性?
unique_ptr相关
/* implement */
内容总结
以上是互联网集市为您收集整理的[c++] Why should I use Smart Pointers全部内容,希望文章能够帮你解决[c++] Why should I use Smart Pointers所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。