##没有躲过的坑--智能指针陷阱
之前博客《[浅析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!
- 前言
- deprecated关键字
- 指针(内存泄露)
- 头文件相互包含(Compiler error C2653: not a class or namespace name)
- 获取一张图片的width和height
- This function or variable may be unsafe.
- 智能指针陷阱
- wstring与string的转换
- windows下chrome浏览器插件不能安装
- 重定义关键字
- 正确释放vector的内存
- 获取设备环境HDC
- 抽象类不能实例化对象(但是你明明定义的不是抽象类)
- 重载赋值运算符的自我赋值
- 程序中的变量未初始化
- 成对使用new和delete时要采取相同的形式
- 意想不到的除数为零
- map的初始化(插入数据)
- 正则表达式截取字符串
- 捕获窗口之外的鼠标消息(钩子还是??)
- 类中的静态成员变量(static or const static)
- 有if就要有else(一定成对)
- map查找结果处理
- 使用using namespace std的坏习惯
- new一个指针数组、以及创建动态二维数组
- 使用太多的全局变量
- 没有及时break出for循环
- vector使用erase后迭代器变成野指针
- C++函数的默认参数(重新定义默认参数)
- 0xC0000005: 读取位置 xxx时发生访问冲突
- std::string初始化、最快速判断字符串为空
- 你开发的软件安装在C盘Program Files (x86)下产生的异常