C++智能指针

由于动态内存使用很容易出问题,例如忘记了释放内存造成内存泄漏,释放正在使用的内存造成非法内存访问等,为了更容易和安全地使用动态内存,标准库提供了三种智能指针来管理动态对象,shared_ptr允许多个智能指针指向同一个对象,unique_ptr则独占所指向的对象,weak_ptr是一种弱引用,指向shared_ptr所管理的对象。

智能指针也是模板,当我们创建智能指针时,必须提供指针可以指向的类型。智能指针的使用方式与普通指针类似,解引用一个智能指针返回它指向的对象,条件判断中使用智能指针的效果就是检测它是否为空。

shared_ptr

最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数。

int main()
{
    shared_ptr p = make_shared(2);
    if (p) {
        cout << *p << endl;
    }
    auto str = make_shared(8, '6');
    cout << *str << endl;
    system("pause");
}

当进行拷贝或赋值操作时,每个shared_ptr都会记录有多少个其它shared_ptr指向相同的对象,当引用计数为0时,shared_ptr会自动释放自己管理的对象。

int main()
{
    shared_ptr p = make_shared(2);
    if (p.unique()) {
        cout << "唯一的" << endl;
    }
    //返回指向对象的shared_ptr数量
    cout << p.use_count() << endl;
    auto a = p;
    cout << p.use_count() << endl;
    system("pause");
}

我们还可以使用new返回的指针来初始化智能指针,接受指针参数的构造函数是explicit的,必须使用直接初始化来初始化一个智能指针。

    //正确
    shared_ptr p1(new int(33));
    //错误,必须使用直接初始化,接受指针参数的构造函数是explicit的
    shared_ptr p2=new int(44);

由于shared_ptr会自动释放内存,所以不要混用普通指针和智能指针,否则可能导致错误。

void printInt(shared_ptr p)
{
    cout << *p << endl;
}

int main()
{
    auto p = new int(22);
    printInt(shared_ptr(p));//内存会被释放
    int i = *p;//错误,p指向的内存已经被释放
    cout << i << endl;//i值不为22
    system("pause");
}

智能指针定义了一个名为get的函数返回原始指针,只有你确定不会delete指针的情况下才能使用get,尤其是永远也不要用get初始化另一个智能指针或为另一个智能指针赋值。

int main()
{
    auto p = make_shared(22);
    cout << *(p.get()) << endl;
    system("pause");
}

与赋值类似,reset可以将管理的指针置空或使之指向另外一个指针,并更新引用计数。

int main()
{
    auto p = make_shared(22);
    p.reset();
    cout << p.use_count() << endl;
    cout << p.get() << endl;
    p.reset(new int(33));
    cout << *p << endl;
    system("pause");
}

默认情况下,当一个shared_ptr要销毁它指向的对象时,会执行delete操作,我们也可以使用自定义的函数代替delete。

class MyClass
{
};

void myDelete(MyClass* obj)
{
    cout << "my delete" << endl;
    delete obj;
}

void testFunc()
{
    auto obj = shared_ptr(new MyClass(), myDelete);
    obj.reset(new MyClass(), myDelete);
}

int main()
{
    
    testFunc();
    system("pause");
}

unique_ptr

和shared_ptr不同,同一时刻只能有一个unique_ptr指向给定的对象,当unique_ptr被销毁时,它所指向的对象也随之销毁,unique_ptr不支持拷贝和赋值。

unique_ptr大部分操作和shared_ptr类似,只是如果想要替换默认delete方法,需要在创建时提供替换函数的类型。

class MyClass
{
};

void myDelete(MyClass* obj)
{
    cout << "my delete" << endl;
    delete obj;
}

void testFunc()
{
    auto obj = unique_ptr(new MyClass(), myDelete);
}

int main()
{
    testFunc();
    system("pause");
}

weak_ptr

weak_ptr是一种不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的对象,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。

int main()
{
    auto p = make_shared(33);
    weak_ptr weakValue = p;

    //与weak_ptr共享对象的shared_ptr的数量
    cout << weakValue.use_count() << endl;
    //测试use_count是否为0
    cout << weakValue.expired() << endl;
    //如果expired为true,则返回空指针,否则返回一个指向对象的shared_ptr
    if (auto newValue = weakValue.lock()) {
        cout << newValue << endl;
    }
    system("pause");
}

智能指针和异常

由于在栈上分配的对象会自动销毁,即使中途发生异常,所以智能指针也能利用这一特性确保异常发生后对象能正常释放。

class MyClass
{
public:
    ~MyClass() { cout << "MyClass Destory..." << endl; }
};

void testFunc()
{
    MyClass obj1;
    auto obj2 = make_shared();
    throw exception();
}

int main()
{
    try{
        testFunc();
    }catch(...){
        cout << "catch exception..." << endl;
    }
    system("pause");
}

你可能感兴趣的:(C++智能指针)