企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
##没有躲过的坑--智能指针陷阱 之前博客《[浅析C++中的智能指针](http://blog.csdn.net/wangshubo1989/article/details/48337955 "智能指针")》讲诉了一些智能指针的东西,可以帮助我们更加方便高效的使用指针,但是凡事都不会很完美。即使你使用智能指针代替了传统的指针,在实战中你还是会遇到很多的坑儿。 现在,就分几个方面:  首先为了简化代码,进行了一些定义: ~~~ class Test { public: Test():m_value(0) { std::cout << "Test::Test" << std::endl; } ~Test() { std::cout << "Test::~Test destructor" << std::endl; } int m_value; }; typedef std::auto_ptr<Test> TestAutoPtr; typedef std::unique_ptr<Test> TestUniquePtr; typedef std::shared_ptr<Test> TestSharedPtr; ~~~ **为什么auto_ptr 被弃用?**  auto_ptr 是第一个智能指针。 但是为什么会被弃用呢?看看一个简单的例子 ~~~ void doSomethig(TestAutoPtr myPtr) { myPtr->m_value = 11; } void AutoPtrTest() { TestAutoPtr myTest(new Test()); doSomethig(myTest); myTest->m_value = 10; } ~~~ 编译上面的代码并试着运行,会有什么样的结果呢?答案是在doSomething执行结束后程序崩溃! 我们可以推断,在doSomething 中,引用计数增加了,但是auto_ptr没有这样的功能。  所以我们应该传递智能指针的引用。但是对于更加复杂的对象,我们就会失去控制。 **为什么 unique_ptr 很好用?**  幸运的是,我们有新的智能指针。在之前的例子中,我们使用std::unique_ptr 代替auto_ptr 这时候,我们会得到编译错误,而不是运行时期的错误。因为,我们不能传递一个unique_ptr给另一个函数。 但是为了可以传递,我们可以使用move把智能指针的所有权进行转移,代码如下: ~~~ doSomethig(std::move(myTest)); ~~~ **如何使用数组和unique_ptr 联系在一起?**  首先我们要明确的是,下面的代码是致命的: ~~~ std::unique_ptr<int> p(new int[10]); // will not work! ~~~ 之所以说上面的代码是致命的是因为可以编译通过。但是当资源被释放掉的时候,只有delete被调用,而不是delete[]。所以,我们如何确保delete[] 被调用呢?  你应该这么干: ~~~ std::unique_ptr<int[]> p(new int[10]); p[0] = 10; ~~~ 对于上面的例子,我们可以这么干: ~~~ std::unique_ptr<Test[]> tests(new Test[3]); ~~~ 这样就会得到我们期望的输出:  Test::Test  Test::Test  Test::Test  Test::~Test destructor  Test::~Test destructor  Test::~Test destructor **为什么使用shared_ptr ?**  通过引用计数来实现shared_ptr ,所以我们这么干: ~~~ std::shared_ptr<Test> sp(new Test()); std::shared_ptr<Test> sp2 = std::make_shared<Test>(); ~~~ 得到这样的输出:  Test::Test  Test::Test  Test::~Test destructor  Test::~Test destructor **如何使用数组和shared_ptr 联系在一起?** ~~~ std::shared_ptr<Test> sp(new Test[2], [](Test *p) { delete [] p; }); ~~~ **如何把智能指针传递给函数?**  看代码: ~~~ void testSharedFunc(std::shared_ptr<Test> sp) { sp->m_value = 10; } void testSharedFuncRef(const std::shared_ptr<Test> &sp) { sp->m_value = 10; } void SharedPtrParamTest() { std::shared_ptr<Test> sp = std::make_shared<Test>(); testSharedFunc(sp); testSharedFuncRef(sp); } ~~~ 只有testSharedFunc 会增加引用计数。 也就是说传递ref没有增加引用计数,那么到底是哪种方式好呢?  视情况而定! **如何对智能指针进行类型转换?**  看看这个代码: ~~~ class BaseA { protected: int a{ 0 }; public: virtual ~BaseA() { } void A(int p) { a = p; } }; class ChildB : public BaseA { private: int b{ 0 }; public: void B(int p) { b = p; } }; ~~~ 毫无疑问,我可以创建一个指向A的智能指针,并初始化为B: ~~~ std::shared_ptr<BaseA> ptrBase = std::make_shared<ChildB>(); ptrBase->A(10); ~~~ 但是如何强制转换呢,把ptrBase指向B呢?你可能这样尝试: ~~~ ChildB *ptrMan = dynamic_cast<ChildB *>(ptrBase.get()); ptrMan->B(10); ~~~ 成功了,但是代价是你只获得了一个普通指针。智能指针的引用计数并没有增加。所以更好的办法就是使用智能指针的转换方法: ~~~ std::shared_ptr<ChildB> ptrChild = std::dynamic_pointer_cast<ChildB>(ptrBase); if (ptrChild) { ptrChild->B(20); std::cout << "use count A: " << ptrBase.use_count() << std::endl; std::cout << "use count B: " << ptrChild.use_count() << std::endl; } ~~~ 通过使用std::dynamic_pointer_cast 你会得到一个shared pointer. **结语:**  智能指针没有用,但是我们应该更加谨慎的使用它们!  stay foolish stay hungry!