智能指针的设计初衷是:
     C++中没有提供自己主动回收内存的机制,每次new对象之后都须要手动delete。稍不注意就memory leak。

智能指针能够解决上面遇到的问题。

C++中常见的智能指针包含(共七种):
     std::auto_ptr
     boost::scoped_ptr
     boost::shared_ptr
     boost::intrusive_ptr
     boost::scoped_array
     boost::shared_array
     boost::weak_ptr
    事实上,智能指针并非指针,它不过一个栈对象而已。
在栈对象的生命周期结束时,智能指针调用析构函数释放其管理的堆内存。
全部的智能指针都重载了'operator->'操作符,用来返回其管理对象的引用。从而能够
运行所管理对象的一些操作。


两个方法:
     - get()
          訪问智能指针包括的裸指针引用
     - reset()
          若传递參数为空或NULL 则智能指针会释放当前管理的内存。

          若传递參数为一个对象 则智能指针会释放当前管理的内存,管理新传入的对象。

假定有以下这个ManagedObj类。
  1. class ManagedObj
  2. {
  3. public:
  4. ManagedObj(int val = 0):m_val(val)
  5. {
  6. cout<<"Obj : "<<m_val<<endl;
  7. }
  8.  
  9. ~ManagedObj()
  10. {
  11. cout<<"~Obj : "<<m_val<<endl;
  12. }
  13.  
  14. void testFun()
  15. {
  16. cout<<"testFun : "<<m_info<<endl;
  17. }
  18.  
  19. public:
  20. string m_info;
  21. int m_val;
  22. };

-> std::auto_ptr

属于STL
在namespace std中
加入头文件 #include <memory>就可以使用。
auto_ptr一般用于管理单个堆内存对象。

看以下这个样例:
  1. // std::auto_ptr
  2. void testAutoPtr1()
  3. {
  4. auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));
  5.  
  6. if (atPtr.get()) // 推断智能指针是否为空
  7. {
  8. atPtr->testFun();
  9.  
  10. atPtr.get()->m_info += " 1st append"; // get() 返回裸指针的引用
  11. atPtr->testFun();
  12.  
  13. (*atPtr).m_info += " 2nd append"; // operator* 返回智能指针管理的对象
  14. (*atPtr).testFun();
  15. }
  16. }
执行结果为:

OK 好像没什么问题。

我们接着測试:
  1. void testAutoPtr2()
  2. {
  3. auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));
  4.  
  5. if (atPtr.get()) // 推断智能指针是否为空
  6. {
  7. auto_ptr<ManagedObj> atPtr2;
  8.  
  9. atPtr2 = atPtr; // 原因在这行代码
  10. atPtr2->testFun();
  11. atPtr->testFun(); // 崩溃在这行代码
  12. }
  13. }
执行结果为:

调试发现 最后一行代码出bug了。
为什么呢?
事实上是atPtr2剥夺了atPtr的内存管理全部权,导致atPtr悬空。

继续測试。

  1. void testAutoPtr3()
  2. {
  3. auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));
  4.  
  5. if (atPtr.get()) // 推断智能指针是否为空
  6. {
  7. atPtr.release();
  8. }
  9. }
执行结果为:

好像又出bug了。
我们并没有看到析构函数被调用的迹象,内存泄漏了。。
(逗我呢 怎么这么多bug?

)


别着急 第三个測试函数正确的写法应该是这种。
  1. void testAutoPtr3()
  2. {
  3. auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));
  4.  
  5. if (atPtr.get()) // 推断智能指针是否为空
  6. {
  7. //ManagedObj* temp = atPtr.release();
  8. //delete temp;
  9.  
  10. // 或者
  11. atPtr.reset();
  12. }
  13. }

这才是我们想要看到的结果。


所以我们也发现。auto_ptr的release()函数仅仅是让出内存的管理权,并没有真正的释放内存。

总结:
     auto_ptr一般用于管理单个堆内存对象。

可是须要注意:

     a. 切记使用 "operator="。万一真用了,就不要再使用旧的对象了。

     b. release()方法不会释放内存 只不过让出全部权。

上面的auto_ptr使用起来确实不是非常方便,并且我们还有注意避开它的使用缺陷。

因此就出现了boost中的一些智能指针,以下一一介绍。

-> boost::scoped_ptr


属于boost库
在namespace boost中
加入头文件 #include<boost/smart_ptr.hpp> 就可以使用。


关于boost库的安装教程 可參考:

与auto_ptr类似。scoped_ptr也可管理单个堆内存的对象,
可是它独享全部权,因此也就避免了auto_ptr的缺陷

OK。上代码測试。

  1. // boost::scoped_ptr
  2. void testScopedPtr()
  3. {
  4. boost::scoped_ptr<ManagedObj> scPtr(new ManagedObj(1, " initialize"));
  5.  
  6. if (scPtr.get())
  7. {
  8. scPtr->testFun();
  9.  
  10. scPtr.get()->m_info += " 1st append"; // get() 返回裸指针的引用
  11. scPtr->testFun();
  12.  
  13. (*scPtr).m_info += " 2nd append"; // operator* 返回智能指针管理的对象
  14. (*scPtr).testFun();
  15.  
  16. //scPtr.release(); // error scoped_ptr 没有成员release
  17.  
  18. //boost::scoped_ptr<ManagedObj> scPtr2;
  19. //scPtr2 = scPtr; // error scoped_ptr<T>::operator=(const scoped_ptr<ManagedObj> &)不可訪问
  20. }
  21. }
执行结果为:

注意凝视部分的代码。
scoped_ptr没有release()函数  屏蔽了operator=操作,
因此不会出现auto_ptr中出现的内存泄漏和崩溃问题。
但这也带来了还有一个新问题。我们无法复制智能指针。

因此出现了接下来的shared_ptr。

-> boost::shared_ptr

属于boost库
在namespace boost中
加入头文件 #include<boost/smart_ptr.hpp> 就可以使用。


因为scoped_ptr不同意赋值 拷贝 独享内存的全部权。
这里的shared_ptr是专门解决智能指针的内存全部权共享这个问题的。
其内部使用了引用计数。
来,測试吧。

  1. // boost::shared_ptr
  2. void testSharedPtr(boost::shared_ptr<ManagedObj> ptr)
  3. {
  4. ptr->testFun();
  5. cout<<"shared_ptr use_count: "<<ptr.use_count()<<endl;
  6. }
  7.  
  8. void testSharedPtr1()
  9. {
  10. boost::shared_ptr<ManagedObj> shPtr(new ManagedObj(1, " initialize"));
  11.  
  12. if (shPtr.get())
  13. {
  14. shPtr->testFun();
  15.  
  16. shPtr.get()->m_info += " 1st append"; // get() 返回裸指针的引用
  17. shPtr->testFun();
  18.  
  19. (*shPtr).m_info += " 2nd append"; // operator* 返回智能指针管理的对象
  20. (*shPtr).testFun();
  21. }
  22.  
  23. cout<<"shared_ptr1 use_count: "<<shPtr.use_count()<<endl;
  24. testSharedPtr(shPtr);
  25. cout<<"shared_ptr1 use_count: "<<shPtr.use_count()<<endl;
  26. //shPtr.release(); // error shared_ptr 没有成员release
  27. }
执行结果为:

能够看到。调用testSharedPtr()函数运行了一次复制操作,智能指针内部的引用计数+1。
在该函数调用结束后,引用计数自己主动-1。
上面介绍的几种智能指针都针对单个对象的内存管理。

事实上智能指针也可管理数组,接下来介绍boost::scoped_array和boost::shared_array。


-> boost::scoped_array

属于boost库
在namespace boost中
加入头文件 #include<boost/smart_ptr.hpp> 就可以使用。

boost::scoped_array用于管理动态数组。也是独享全部权的。


上代码:
  1. // boost::scoped_array
  2. void testScopedArray()
  3. {
  4. boost::scoped_array<ManagedObj> scArr(new ManagedObj[2]); // 动态数组初始化
  5.  
  6. if (scArr.get())
  7. {
  8. scArr[0].testFun();
  9.  
  10. scArr.get()[0].m_info += " [0] 1st append";
  11. scArr[0].testFun();
  12.  
  13. //(*scArr)[0].m_info += " 2st append"; // error scoped_array没有重载operator*
  14. //(*scArr)[0].testFun();
  15.  
  16. //scArr[0].release(); // error scoped_array 没有成员release
  17.  
  18. boost::scoped_array<ManagedObj> scArr2;
  19. //scArr2 = scArr; // error operator=不可訪问 屏蔽了operator= 禁止拷贝
  20. }
  21. }
执行结果为:

boost::scoped_array的使用和boost::scoped_ptr大致几乎相同。
都禁止拷贝 独享全部权。

注意:
     boost::scoped_array没有重载operator*操作符

-> boost::shared_array

属于boost库
在namespace boost中
加入头文件 #include<boost/smart_ptr.hpp> 就可以使用。


内部使用了引用计数,解决參数传递和拷贝赋值时的问题。


以下给出代码測试:
  1. // boost::shared_array
  2. void testSharedArray(boost::shared_array<ManagedObj> pArr)
  3. {
  4. cout<<"shared_arr use_count: "<<pArr.use_count()<<endl;
  5. boost::shared_array<ManagedObj> pTempArr;
  6. pTempArr = pArr;
  7. cout<<"shared_arr use_count: "<<pArr.use_count()<<endl;
  8. }
  9.  
  10. void testSharedArray1()
  11. {
  12. boost::shared_array<ManagedObj> shArr(new ManagedObj[2]);
  13.  
  14. if (shArr.get())
  15. {
  16. shArr[0].testFun();
  17.  
  18. shArr.get()[0].m_info += " [0] 1st append";
  19. shArr[0].testFun();
  20. shArr[1].testFun();
  21.  
  22. shArr.get()[0].m_info += " [1] 1st append";
  23. shArr[1].testFun();
  24. //(*shArr)[0].m_info += " [0] 2nd append"; // error 没有重载operator*操作符
  25. }
  26.  
  27. cout<<"shared_arr1 use_count: "<<shArr.use_count()<<endl;
  28. testSharedArray(shArr);
  29. cout<<"shared_arr1 use_count: "<<shArr.use_count()<<endl;
  30. }
执行结果为:


-> boost::weak_ptr

属于boost库
在namespace boost中
加入头文件 #include<boost/smart_ptr.hpp> 就可以使用。

若我们只关心是否能使用对象。而不关心内部的引用计数。
boost::weak_ptr 是 boost::shared_ptr 的观察者(Observer)对象,
意味着boost::weak_ptr仅仅对boost::shared_ptr引用。可是并不更新
其引用计数。被观察的shared_ptr失效后,weak_ptr对应也失效。


上測试代码:
  1. // boost::weak_ptr
  2. void testWeakPtr()
  3. {
  4. boost::weak_ptr<ManagedObj> wPtr;
  5. boost::shared_ptr<ManagedObj> shPtr(new ManagedObj(1, "initialize"));
  6.  
  7. cout << "testWeakPtr boost::shared_ptr UseCount: " << shPtr.use_count() << endl;
  8. wPtr = shPtr;
  9. cout << "testWeakPtr boost::shared_ptr UseCount: " << shPtr.use_count() << endl;
  10. }
执行结果为:

我们发现赋值操作并没有更改引用计数。
boost::weak_ptr很多其它用于以下这样的场合:
     在基类中定义一个weak_ptr,用于观察其子类中的shared_ptr。这样基类仅仅要看自己的weak_ptr
是否为空就知道子类有没对自己赋值,而不影响子类中shared_ptr的引用计数。从而减少复杂度。更好管理对象。

-> boost::intrusive_ptr

属于boost库
在namespace boost中
加入头文件 #include<boost/smart_ptr.hpp> 就可以使用。

intrusive_ptr是一种插入式智能指针,其内部没有引用计数,
须要自己增加引用计数,否则会编译错误。

OK 到这儿为止,七种智能指针基本上都大致介绍完了。

參考:

http://blog.csdn.net/xt_xiaotian/article/details/5714477

完整的代码在这里

  1. #include <iostream>
  2. #include <memory>
  3. #include <string>
  4. #include <boost/smart_ptr.hpp> // add header file
  5.  
  6. // namespace
  7. using namespace std;
  8. using namespace boost;
  9.  
  10. // heap obj class
  11. class ManagedObj
  12. {
  13. public:
  14. ManagedObj(int val = 0, string info = "")
  15. :m_val(val), m_info(info)
  16. {
  17. cout<<"Obj : "<<m_val<<m_info<<endl;
  18. }
  19.  
  20. ~ManagedObj()
  21. {
  22. cout<<"~Obj : "<<m_val<<m_info<<endl;
  23. }
  24.  
  25. void testFun()
  26. {
  27. cout<<"testFun : "<<m_info<<endl;
  28. }
  29.  
  30. public:
  31. string m_info;
  32. int m_val;
  33. };
  34.  
  35. // std::auto_ptr
  36. void testAutoPtr1()
  37. {
  38. auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));
  39.  
  40. if (atPtr.get()) // 推断智能指针是否为空
  41. {
  42. atPtr->testFun();
  43.  
  44. atPtr.get()->m_info += " 1st append"; // get() 返回裸指针的引用
  45. atPtr->testFun();
  46.  
  47. (*atPtr).m_info += " 2nd append"; // operator* 返回智能指针管理的对象
  48. (*atPtr).testFun();
  49. }
  50. }
  51.  
  52. void testAutoPtr2()
  53. {
  54. auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));
  55.  
  56. if (atPtr.get()) // 推断智能指针是否为空
  57. {
  58. auto_ptr<ManagedObj> atPtr2;
  59.  
  60. atPtr2 = atPtr;
  61. atPtr2->testFun();
  62. atPtr->testFun();
  63. }
  64. }
  65.  
  66. void testAutoPtr3()
  67. {
  68. auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));
  69.  
  70. if (atPtr.get()) // 推断智能指针是否为空
  71. {
  72. //ManagedObj* temp = atPtr.release();
  73. //delete temp;
  74.  
  75. // 或者
  76. atPtr.reset();
  77. }
  78. }
  79.  
  80. // boost::scoped_ptr
  81. void testScopedPtr()
  82. {
  83. boost::scoped_ptr<ManagedObj> scPtr(new ManagedObj(1, " initialize"));
  84.  
  85. if (scPtr.get())
  86. {
  87. scPtr->testFun();
  88.  
  89. scPtr.get()->m_info += " 1st append"; // get() 返回裸指针的引用
  90. scPtr->testFun();
  91.  
  92. (*scPtr).m_info += " 2nd append"; // operator* 返回智能指针管理的对象
  93. (*scPtr).testFun();
  94.  
  95. //scPtr.release(); // error scoped_ptr 没有成员release
  96.  
  97. //boost::scoped_ptr<ManagedObj> scPtr2;
  98. //scPtr2 = scPtr; // error scoped_ptr<T>::operator=(const scoped_ptr<ManagedObj> &)不可訪问
  99. }
  100. }
  101.  
  102. // boost::shared_ptr
  103. void testSharedPtr(boost::shared_ptr<ManagedObj> ptr)
  104. {
  105. ptr->testFun();
  106. cout<<"shared_ptr use_count: "<<ptr.use_count()<<endl;
  107. }
  108.  
  109. void testSharedPtr1()
  110. {
  111. boost::shared_ptr<ManagedObj> shPtr(new ManagedObj(1, " initialize"));
  112.  
  113. if (shPtr.get())
  114. {
  115. shPtr->testFun();
  116.  
  117. shPtr.get()->m_info += " 1st append"; // get() 返回裸指针的引用
  118. shPtr->testFun();
  119.  
  120. (*shPtr).m_info += " 2nd append"; // operator* 返回智能指针管理的对象
  121. (*shPtr).testFun();
  122. }
  123.  
  124. cout<<"shared_ptr1 use_count: "<<shPtr.use_count()<<endl;
  125. testSharedPtr(shPtr);
  126. cout<<"shared_ptr1 use_count: "<<shPtr.use_count()<<endl;
  127.  
  128. //shPtr.release(); // error shared_ptr 没有成员release
  129. }
  130.  
  131. // boost::scoped_array
  132. void testScopedArray()
  133. {
  134. boost::scoped_array<ManagedObj> scArr(new ManagedObj[2]); // 动态数组初始化
  135.  
  136. if (scArr.get())
  137. {
  138. scArr[0].testFun();
  139.  
  140. scArr.get()[0].m_info += " [0] 1st append";
  141. scArr[0].testFun();
  142.  
  143. //(*scArr)[0].m_info += " 2st append"; // error scoped_array没有重载operator*
  144. //(*scArr)[0].testFun();
  145.  
  146. //scArr[0].release(); // error scoped_array 没有成员release
  147.  
  148. boost::scoped_array<ManagedObj> scArr2;
  149. //scArr2 = scArr; // error operator=不可訪问 屏蔽了operator= 禁止拷贝
  150. }
  151. }
  152.  
  153. // boost::shared_array
  154. void testSharedArray(boost::shared_array<ManagedObj> pArr)
  155. {
  156. cout<<"shared_arr use_count: "<<pArr.use_count()<<endl;
  157.  
  158. boost::shared_array<ManagedObj> pTempArr;
  159. pTempArr = pArr;
  160. cout<<"shared_arr use_count: "<<pArr.use_count()<<endl;
  161. }
  162.  
  163. void testSharedArray1()
  164. {
  165. boost::shared_array<ManagedObj> shArr(new ManagedObj[2]);
  166.  
  167. if (shArr.get())
  168. {
  169. shArr[0].testFun();
  170.  
  171. shArr.get()[0].m_info += " [0] 1st append";
  172. shArr[0].testFun();
  173. shArr[1].testFun();
  174.  
  175. shArr.get()[1].m_info += " [1] 1st append";
  176. shArr[1].testFun();
  177. //(*shArr)[0].m_info += " [0] 2nd append"; // error 没有重载operator*操作符
  178. }
  179.  
  180. cout<<"shared_arr1 use_count: "<<shArr.use_count()<<endl;
  181. testSharedArray(shArr);
  182. cout<<"shared_arr1 use_count: "<<shArr.use_count()<<endl;
  183. }
  184.  
  185. // boost::weak_ptr
  186. void testWeakPtr()
  187. {
  188. boost::weak_ptr<ManagedObj> wPtr;
  189. boost::shared_ptr<ManagedObj> shPtr(new ManagedObj(1, "initialize"));
  190.  
  191. cout << "testWeakPtr boost::shared_ptr UseCount: " << shPtr.use_count() << endl;
  192. wPtr = shPtr;
  193. cout << "testWeakPtr boost::shared_ptr UseCount: " << shPtr.use_count() << endl;
  194. }
  195.  
  196. // boost::intrusive_ptr
  197. void testIntrusivePtr()
  198. {
  199. //boost::intrusive_ptr<ManagedObj> intPtr(new ManagedObj[1], false); // error 要自己加入引用计数
  200. }
  201.  
  202. // main function
  203. int main(void)
  204. {
  205. // -----std::auto_ptr-----
  206. //testAutoPtr();
  207. //testAutoPtr2();
  208. //testAutoPtr3();
  209.  
  210. // -----boost::scoped_ptr-----
  211. //testScopedPtr();
  212.  
  213. // -----boost::shared_ptr-----
  214. //testSharedPtr1();
  215.  
  216. // -----boost::scoped_array-----
  217. //testScopedArray();
  218.  
  219. // -----boost::shared_array-----
  220. //testSharedArray1();
  221.  
  222. // -----boost::weak_ptr-----
  223. testWeakPtr();
  224.  
  225. return 0;
  226. }

你说你会C++? —— 智能指针的更多相关文章

  1. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  2. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  3. C++智能指针

    引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...

  4. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

  5. 智能指针shared_ptr的用法

    为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...

  6. 智能指针unique_ptr的用法

    unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...

  7. 基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  8. C++ 引用计数技术及智能指针的简单实现

    一直以来都对智能指针一知半解,看C++Primer中也讲的不够清晰明白(大概是我功力不够吧).最近花了点时间认真看了智能指针,特地来写这篇文章. 1.智能指针是什么 简单来说,智能指针是一个类,它对普 ...

  9. C++11智能指针读书笔记;

    智能指针是一个类对象,而非一个指针对象. 原始指针:通过new建立的*指针 智能指针:通过智能指针关键字(unique_ptr, shared_ptr ,weak_ptr)建立的指针 它的一种通用实现 ...

  10. 「C++」理解智能指针

    维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...

随机推荐

  1. 什么是老板思维,什么是员工思维,深有体会,最近被N个行业洗脑……

    什么是老板思维,什么是员工思维,深有体会,最近被N个行业洗脑……

  2. BZOJ1835: [ZJOI2010]base 基站选址(线段树优化Dp)

    Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...

  3. Linux 创建新用户并添加到sudo用户组

    附上一份相当奢华的文档:  https://www.cnblogs.com/jxhd1/p/6528574.html 添加用户到组 usermod -a -G sudo newone

  4. ZOJ 3674 Search in the Wiki(字典树 + map + vector)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4917 题意:每一个单词都一些tips单词. 先输入n个单词和他们的t ...

  5. actionbar-去掉背景的阴影

    今天发现一个问题,就是actionbar跟界面的交界处,会有一个阴影,通过调查发现,这个阴影是actionbar的.然后通过在网上找资料,完美解决了问题.解决方法如下 1.在这个actionbar所在 ...

  6. Impala的安装(含使用CM安装 和 手动安装)(图文详解)

    Impala有两种安装方式: 1)使用CM安装Impala 2)手动安装Impala 注意:Impala不支持在Debian/Ubuntu, SuSE, RHEL/CentOS 6.5系统中安装. 基 ...

  7. js上传文件(图片)的格式和大小限制

    如果你想快速解决这个问题,看本文就够了.查了好多资料,终于解决了,太耗时间了,本文留给给后来者,希望你们工作的更轻松 本文保存为.html文件用浏览器打开即可测试功能 <form id=&quo ...

  8. (转)Linux下查看Nginx Apache MySQL的并发连接数和连接状态

    转自: http://www.ha97.com/4106.html 1.查看Web服务器(Nginx Apache)的并发请求数及其TCP连接状态:netstat -n | awk '/^tcp/ { ...

  9. WPF MVVM示例自定义模板数据绑定

    在触摸屏设备上.由于列表是的信息展示不是非常直观和便捷操作. 所以也就出现了很多用面板控件:类似win10的Metro风格, 所以抽空做了一个WPF面板控件. 话不多上 , 先上一个示例图. 为了便于 ...

  10. mycat基本概念及读写分离一

    mycat基本概念及读写分离一 目录(?)[+] 安装与启动 mycat目录介绍 mycat三个最重要配置文件 验证读写分离 安装与启动 linux下可以下载Mycat-server-xxxxx.li ...