深入学习C++智能指针之shared_ptr与右值引用的方法
本文将介绍C++中的智能指针shared_ptr和右值引用的概念及其用法,其中注意点将在示例中一并说明。
shared_ptr
shared_ptr是C++11中的智能指针,用于管理动态分配内存的生命周期。shared_ptr采用引用计数的机制,每个shared_ptr都能访问同一块内存,当最后一个指向该内存的shared_ptr被销毁时,内存就会被释放。使用shared_ptr能够有效地避免内存泄漏。
shared_ptr的创建
shared_ptr的创建可以通过直接赋值或者make_shared函数来实现。
直接赋值方式
//示例1:
//普通指针的创建
int *p = new int(10);
//shared_ptr的创建
shared_ptr<int> sp(p);
shared_ptr<int>
用于指定shared_ptr的类型,sp
是shared_ptr的对象名,p
是普通指针的名称。当sp
析构时,它会自动释放p
所指向的内存。
make_shared函数
make_shared函数能够更加方便地创建shared_ptr。
//示例2:
auto sp1 = make_shared<int>(10); //等同于shared_ptr<int> sp(new int(10))
auto sp2 = make_shared<string>("hello"); //等同于shared_ptr<string> sp(new string("hello"))
make_shared函数可以更加简明地创建shared_ptr,类型名和内存分配都通过参数确定。
shared_ptr的使用
shared_ptr的使用方法和常规指针类似,可以通过解引用符号*
和箭头符号->
来访问存储在shared_ptr中的对象。
//示例3:
auto sp1 = make_shared<int>(10);
auto sp2 = sp1;
cout << *sp1 << " " << *sp2 << endl; //输出:10 10
*sp1 = 20;
cout << *sp1 << " " << *sp2 << endl; //输出:20 20
示例中,sp2
也指向了sp1
所指向的内存,所以*sp1
和*sp2
的值相同,当对*sp1
赋值后,两个指针所指向的值均发生了变化。
shared_ptr的注意点
在使用shared_ptr的过程中,需要注意以下几点。
避免循环引用
循环引用是指两个或者多个对象之间相互引用,这种情况常常会导致内存泄漏。使用shared_ptr的时候,尤其要注意避免循环引用造成的问题。
//示例4:
struct B;
struct A
{
shared_ptr<B> m_Bptr;
~A() {cout << "A deleted" << endl;}
};
struct B
{
shared_ptr<A> m_Aptr;
~B() {cout << "B deleted" << endl;}
};
void Test()
{
shared_ptr<A> a(new A);
shared_ptr<B> b(new B);
a->m_Bptr = b; //A实例持有B实例的shared_ptr
b->m_Aptr = a; //B实例持有A实例的shared_ptr
}
在示例4中,A类和B类相互持有对方的shared_ptr,在函数结束时,由于相互持有,导致shared_ptr引用计数不为0,出现内存泄漏的问题。这种情况可以通过使用weak_ptr等方式来避免。
非空判断
在使用shared_ptr的时候,需要对其进行非空判断,以避免使用空指针造成程序崩溃的问题。
//示例5:
void Test(shared_ptr<int> sp)
{
if(sp) //对shared_ptr进行非空判断
{
cout << *sp << endl;
}
}
int main()
{
shared_ptr<int> sp;
Test(sp);
return 0;
}
在示例5中,如果sp为null,则直接忽略某些逻辑,以避免空指针的使用。
右值引用
右值引用是与左值引用对应的概念,右值指的是表达式传递给函数的临时变量或者和常量,通过右值引用,可以将右值直接绑定到函数中,从而避免复制和引用操作。
右值引用的创建
右值引用使用语法为:类型名&& 变量名
。
//示例6:
void Func(int&& value)
{
cout << value << endl;
}
int main()
{
int a = 10;
Func(a + 3); //将表达式a+3作为右值直接传递给函数Func
return 0;
}
在示例6中,a + 3
是一个临时变量,通过右值引用,可以将其直接传递给函数Func
,以避免复制。在函数中,需要使用std::move来转移右值引用,避免出现悬垂指针的问题。
右值引用的注意点
在使用右值引用时,需要注意以下几点。
不能返回局部变量的引用
右值引用不能返回指向局部变量的指针或者引用,因为局部变量的生命周期与函数调用结束时一致。
//示例7:
int&& Func()
{
int value = 10;
return std::move(value); //error: 对 'value' 做右值引用不能将 'value' 作为 'int&&' 的初始值
}
int main()
{
int&& a = Func();
cout << a << endl;
return 0;
}
在示例7中,Func
函数返回一个指向局部变量value
的右值引用,在返回时value
已被销毁,导致悬垂指针的问题。
左值和右值的区别
在使用右值引用时,需要正确地区分左值和右值,以免出现不必要的问题。
//示例8:
void Func(int& value) //对左值参考
{
cout << "左值" << endl;
}
void Func(int&& value) //对右值引用
{
cout << "右值" << endl;
}
int main()
{
int a = 10;
Func(a); //输出“左值”
Func(10); //输出“右值”
return 0;
}
在示例8中,对左值的引用和对右值的引用都是合法的,需要根据实际情况选择正确的引用方式。
总结
本文介绍了C++11中的智能指针shared_ptr和右值引用,包括它们的创建和使用方法,以及需要注意的细节。通过学习本文,可以更加清晰地理解这些概念,并能够灵活应用到实际编程中。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入学习C++智能指针之shared_ptr与右值引用的方法 - Python技术站