智能指针使用及详细解析

智能指针

概念

在c++中,动态内存的管理式通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。动态内存的使用很容易出现问题,因为确保在正确的时间释放内存是极其困难的。有时使用完对象后,忘记释放内存,造成内存泄漏的问题。

所谓的智能指针本质就是一个类模板,它可以创建任意的类型的指针对象,当智能指针对象使用完后,对象就会自动调用析构函数去释放该指针所指向的空间

其实是RALL的思想。
RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:

  • 不需要显式地释放资源。
  • 采用这种方式,对象所需的资源在其生命期内始终保持有效。

下面是智能指针的基本框架,所有的智能指针类模板中都需要包含一个指针对象,构造函数和析构函数。
在这里插入图片描述

为什么使用智能指针

一句话带过:智能指针就是帮我们C++程序员管理动态分配的内存的,它会帮助我们自动释放new出来的内存,从而避免内存泄漏!

如下例子就是内存泄露的例子:

#include <iostream>
#include <string>
#include <memory>

using namespace std;


// 动态分配内存,没有释放就return
void memoryLeak1() {
	string *str = new string("动态分配内存!");
	return;
}

// 动态分配内存,虽然有些释放内存的代码,但是被半路截胡return了
int memoryLeak2() {
	string *str = new string("内存泄露!");

	// ...此处省略一万行代码

	// 发生某些异常,需要结束函数
	if (1) {
		return -1;
	}
	/
	// 另外,使用try、catch结束函数,也会造成内存泄漏!
	/

	delete str;	// 虽然写了释放内存的代码,但是遭到函数中段返回,使得指针没有得到释放
	return 1;
}


int main(void) {

	memoryLeak1();

	memoryLeak2();

	return 0;
} 

memoryLeak1函数中,new了一个字符串指针,但是没有delete就已经return结束函数了,导致内存没有被释放,内存泄露!

memoryLeak2函数中,new了一个字符串指针,虽然在函数末尾有些释放内存的代码delete str,但是在delete之前就已经return了,所以内存也没有被释放,内存泄露!

使用指针,我们没有释放,就会造成内存泄露。但是我们使用普通对象却不会!

所以我们要把分配的动态内存都交由有生命周期的对象来处理,那么在对象过期时,让它的析构函数删除指向的内存。

智能指针就是通过这个原理来解决指针自动释放的问题!

智能指针使用

智能指针的使用跟普通指针类似,可以使用运算符“ * " 和 ” -> "去获得指向的对象,

为什么智能指针可以像普通指针那样使用???

因为其里面重载了 * 和 -> 运算符, * 返回普通对象,而 -> 返回指针对象。

在这里插入图片描述

C++ 提供了多种智能指针:

C++98 提供了 auto_ptr 模板的解决方案
C++11 增加unique_ptr、shared_ptr 和weak_ptr

智能指针的三个常用函数:

智能指针的常用函数

get() 获取智能指针托管的指针地址.
// 定义智能指针
auto_ptr<Test> test(new Test);

Test *tmp = test.get();		// 获取指针返回
cout << "tmp->debug:" << tmp->getDebug() << endl;

但我们一般不会这样使用,因为都可以直接使用智能指针去操作,除非有一些特殊情况。
函数原型:

_NODISCARD _Ty * get() const noexcept
{	// return wrapped pointer
	return (_Myptr);
}
reset() 重置智能指针托管的内存地址,如果地址不一致,原来的会被析构掉
// 定义智能指针
auto_ptr<Test> test(new Test);

test.reset();			// 释放掉智能指针托管的指针内存,并将其置NULL

test.reset(new Test());	// 释放掉智能指针托管的指针内存,并将参数指针取代之

reset函数会将参数的指针(不指定则为NULL),与托管的指针比较,如果地址不一致,那么就会析构掉原来托管的指针,然后使用参数的指针替代之。然后智能指针就会托管参数的那个指针了。

函数原型:

void reset(_Ty * _Ptr = nullptr)
{	// destroy designated object and store new pointer
	if (_Ptr != _Myptr)
		delete _Myptr;
	_Myptr = _Ptr;
}

auto_ptr

auto_ptr 是c++ 98定义的智能指针模板,其定义了管理指针的对象,可以将new 获得(直接或间接)的地址赋给这种对象。当对象过期时,其析构函数将使用delete 来释放内存!

它采取的措施是管理权转移的思想,也就是原对象拷贝给新对象的时候,原对象就会被设置为nullptr,此时就只有新对象指向一块资源空间。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
如果auto_ptr调用拷贝构造函数或者赋值重载函数后,如果再去使用原来的对象的话,那么整个程序就会崩溃掉(因为原来的对象被设置为nullptr),这对程序是有很大的伤害的.所以很多公司会禁用auto_ptr智能指针。

C++11 后auto_ptr 已经被“抛弃”,已使用unique_ptr替代!C++11后不建议使用auto_ptr。

auto_ptr 被C++11抛弃的主要原因

  1. 复制或者赋值都会改变资源的所有权
  2. 在STL容器中使用auto_ptr存在着重大风险,因为容器内的元素必须支持可复制和可赋值
  3. 不支持对象数组的内存管理

unique_ptr

C++11用更严谨的unique_ptr 取代了auto_ptr!
unique_ptr 和 auto_ptr用法几乎一样,除了一些特殊。

unique_ptr特性

1、基于排他所有权模式:两个指针不能指向同一个资源
在这里插入图片描述
2、在 STL 容器中使用unique_ptr,不允许直接赋值
3、支持对象数组的内存管理

// 会自动调用delete [] 函数去释放内存
unique_ptr<int[]> array(new int[5]);	// 支持这样定义

shared_ptr

shared_ptr允许多个智能指针可以指向同一块资源,并且能够保证共享的资源只会被释放一次,因此是程序不会崩溃掉。

shared_ptr的原理

shared_ptr采用的是引用计数原理来实现多个shared_ptr对象之间共享资源:

  • shared_ptr在内部会维护着一份引用计数,用来记录该份资源被几个对象共享。
  • 当一个shared_ptr对象被销毁时(调用析构函数),析构函数内就会将该计数减1。
  • 如果引用计数减为0后,则表示自己是最后一个使用该资源的shared_ptr对象,必须释放资源。
  • 如果引用计数不是0,就说明自己还有其他对象在使用,则不能释放该资源,否则其他对象就成为野指针。
    在这里插入图片描述
    销毁过程:
    在这里插入图片描述
    举例:
class Person {
public:
	Person(int v) {
		this->no = v;
		cout << "构造函数 \t no = " << this->no << endl;
	}

	~Person() {
		cout << "析构函数 \t no = " << this->no << endl;
	}

private:
	int no;
};

// 仿函数,内存删除
class DestructPerson {
public:
	void operator() (Person *pt) {
		cout << "DestructPerson..." << endl;
		delete pt;
	}
};
引用计数的使用

调用use_count函数可以获得当前托管指针的引用计数。

shared_ptr<Person> sp1;

shared_ptr<Person> sp2(new Person(2));

// 获取智能指针管控的共享指针的数量	use_count():引用计数
cout << "sp1	use_count() = " << sp1.use_count() << endl;
cout << "sp2	use_count() = " << sp2.use_count() << endl << endl;

// 共享
sp1 = sp2;

cout << "sp1	use_count() = " << sp1.use_count() << endl;
cout << "sp2	use_count() = " << sp2.use_count() << endl << endl;

shared_ptr<Person> sp3(sp1);
cout << "sp1	use_count() = " << sp1.use_count() << endl;
cout << "sp2	use_count() = " << sp2.use_count() << endl;
cout << "sp2	use_count() = " << sp3.use_count() << endl << endl;

如上代码,sp1 = sp2; 和 shared_ptr< Person > sp3(sp1);就是在使用引用计数了。

sp1 = sp2; --> sp1和sp2共同托管同一个指针,所以他们的引用计数为2;

shared_ptr< Person > sp3(sp1); --> sp1和sp2和sp3共同托管同一个指针,所以他们的引用计数为3;

在这里插入图片描述

构造
  1. shared_ptr< T > sp1; 空的shared_ptr,可以指向类型为T的对象

    shared_ptr<Person> sp1;
    Person *person1 = new Person(1);
    sp1.reset(person1);	// 托管person1
    
  2. shared_ptr< T > sp2(new T()); 定义shared_ptr,同时指向类型为T的对象

    shared_ptr<Person> sp2(new Person(2));
    shared_ptr<Person> sp3(sp1);
    
  3. shared_ptr<T[]> sp4; 空的shared_ptr,可以指向类型为T[]的数组对象 C++17后支持

    shared_ptr<Person[]> sp4;
    
  4. shared_ptr<T[]> sp5(new T[] { … }); 指向类型为T的数组对象 C++17后支持

    shared_ptr<Person[]> sp5(new Person[5] { 3, 4, 5, 6, 7 });
    
  5. shared_ptr< T > sp6(NULL, D()); //空的shared_ptr,接受一个D类型的删除器,使用D释放内存

    shared_ptr<Person> sp6(NULL, DestructPerson());
    
  6. shared_ptr< T > sp7(new T(), D()); //定义shared_ptr,指向类型为T的对象,接受一个D类型的删除器,使用D删除器来释放内存

    shared_ptr<Person> sp7(new Person(8), DestructPerson());
    
初始化
  1. 构造函数

    shared_ptr<int> up1(new int(10));  // int(10) 的引用计数为1
    shared_ptr<int> up2(up1);  // 使用智能指针up1构造up2, 此时int(10) 引用计数为2
    
  2. 使用make_shared 初始化对象,分配内存效率更高(推荐使用)
    make_shared函数的主要功能是在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr; 用法:

    make_shared<类型>(构造类型对象需要的参数列表);

    shared_ptr<int> up3 = make_shared<int>(2); // 多个参数以逗号','隔开,最多接受十个
    shared_ptr<string> up4 = make_shared<string>("字符串");
    shared_ptr<Person> up5 = make_shared<Person>(9);
    

    赋值:

    shared_ptrr<int> up1(new int(10));  // int(10) 的引用计数为1
    shared_ptr<int> up2(new int(11));   // int(11) 的引用计数为1
    up1 = up2;	// int(10) 的引用计数减1,计数归零内存释放,up2共享int(11)给up1, int(11)的引用计数为2
    
主动释放对象
	shared_ptrr<int> up1(new int(10));
	up1 = nullptr ;	// int(10) 的引用计数减1,计数归零内存释放 
	// 或
	up1 = NULL; // 作用同上 
重置

p.reset() ; 将p重置为空指针,所管理对象引用计数 减1

p.reset(p1); 将p重置为p1(的值),p 管控的对象计数减1,p接管对p1指针的管控

p.reset(p1,d); 将p重置为p1(的值),p 管控的对象计数减1并使用d作为删除器

p1是一个指针!

交换

p1 和 p2 是智能指针

std::swap(p1,p2); // 交换p1 和p2 管理的对象,原对象的引用计数不变
p1.swap(p2);    // 交换p1 和p2 管理的对象,原对象的引用计数不变
shared_ptr使用陷阱
1. 互相引用的时候,就会出现循环引用的现象 造成无法释放资源

如下代码:
Boy类中有Girl的智能指针;
Girl类中有Boy的智能指针;
当他们交叉互相持有对方的管理对象时…

#include <iostream>
#include <string>
#include <memory>

using namespace std;

class Girl;

class Boy {
public:
	Boy() {
		cout << "Boy 构造函数" << endl;
	}

	~Boy() {
		cout << "~Boy 析构函数" << endl;
	}

	void setGirlFriend(shared_ptr<Girl> _girlFriend) {
		this->girlFriend = _girlFriend;
	}

private:
	shared_ptr<Girl> girlFriend;
};

class Girl {
public:
	Girl() {
		cout << "Girl 构造函数" << endl;
	}

	~Girl() {
		cout << "~Girl 析构函数" << endl;
	}

	void setBoyFriend(shared_ptr<Boy> _boyFriend) {
		this->boyFriend = _boyFriend;
	}

private:
	shared_ptr<Boy> boyFriend;
};


void useTrap() {
	shared_ptr<Boy> spBoy(new Boy());
	shared_ptr<Girl> spGirl(new Girl());

	// 陷阱用法
	spBoy->setGirlFriend(spGirl);
	spGirl->setBoyFriend(spBoy);
	// 此时boy和girl的引用计数都是2
}


int main(void) {
	useTrap();

	system("pause");
	return 0;
}

运行截图:
在这里插入图片描述
可以看出,程序结束了,但是并没有释放内存,这是为什么呢???

如下图:
当我们执行useTrap函数时,注意,是没有结束此函数,boy和girl指针其实是被两个智能指针托管的,所以他们的引用计数是2

在这里插入图片描述
seTrap函数结束后,函数中定义的智能指针被清掉,boy和girl指针的引用计数减1,还剩下1,对象中的智能指针还是托管他们的,所以函数结束后没有将boy和gilr指针释放的原因就是于此。
在这里插入图片描述
所以在使用shared_ptr智能指针时,要注意避免对象交叉使用智能指针的情况! 否则会导致内存泄露!

当然,这也是有办法解决的,那就是使用weak_ptr弱指针。

针对上面的情况,还讲一下另一种情况。如果是单方获得管理对方的共享指针,那么这样着是可以正常释放掉的!
例如:

void useTrap() {
	shared_ptr<Boy> spBoy(new Boy());
	shared_ptr<Girl> spGirl(new Girl());

	// 单方获得管理
	//spBoy->setGirlFriend(spGirl);
	spGirl->setBoyFriend(spBoy);	
}

在这里插入图片描述

反过来也是一样的!

这是什么原理呢?

首先释放spBoy,但是因为girl对象里面的智能指针还托管着boy,boy的引用计数为2,所以释放spBoy时,引用计数减1,boy的引用计数为1;

在释放spGirl,girl的引用计数减1,为零,开始释放girl的内存,因为girl里面还包含有托管boy的智能指针对象,所以也会进行boyFriend的内存释放,boy的引用计数减1,为零,接着开始释放boy的内存。最终所有的内存都释放了。

2.不要把一个原生指针给多个智能指针管理;
int *x = new int(10);

unique_ptr< int > up1(x);

unique_ptr< int > up2(x);

// 警告! 以上代码使up1 up2指向同一个内存,非常危险

或以下形式:

up1.reset(x);

up2.reset(x);
3.禁止delete 智能指针get 函数返回的指针;

如果我们主动释放掉get 函数获得的指针,那么智能 指针内部的指针就变成野指针了,析构时造成重复释放,带来严重后果!

禁止用任何类型智能指针get 函数返回的指针去初始化另外一个智能指针!

shared_ptr< int > sp1(new int(10));

// 一个典型的错误用法 shared_ptr< int > sp4(sp1.get());

weak_ptr

weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少同时weak_ptr 没有重载*和-> .但可以使用 lock 获得一个可用的 shared_ptr 对象。
在这里插入图片描述

shared_from_this

enable_shared_from_this是一个模板类,定义于头文件<memory>,其原型为:

template< class T > class enable_shared_from_this;

    std::enable_shared_from_this 能让一个对象(假设其名为 t ,且已被一个 std::shared_ptr 对象 pt 管理)安全地生成其他额外的 std::shared_ptr 实例(假设名为 pt1, pt2, ... ) ,它们与 pt 共享对象 t 的所有权。

    若一个类 T 继承 std::enable_shared_from_this<T> ,则会为该类 T 提供成员函数:shared_from_this 。 当 T 类型对象 t 被一个为名为 pt std::shared_ptr<T> 类对象管理时,调用 T::shared_from_this 成员函数,将会返回一个新的 std::shared_ptr<T> 对象,它与 pt 共享 t 的所有权。

使用原因

  1. 把当前类对象作为参数传给其他函数时,为什么要传递share_ptr呢?直接传递this指针不可以吗?一个裸指针传递给调用者,谁也不知道调用者会干什么?假如调用者delete了该对象,而share_tr此时还指向该对象。

  2. 这样传递share_ptr可以吗?share_ptr <this>这样会造成2个非共享的share_ptr指向一个对象,最后造成2次析构该对象。

举例:

      当你想使用一个类的某个成员函数返回指向这个类的指针的时候,可以这样写

class A
{
public:
	A(int y=0):x(y){ }
	A* getthis()
	{
		return this;
	}
	int x;
};
int main (void) 
{
	A a;
	cout<<a.x<<endl;
	A*p=a.getthis();
	p->x=1;
	cout<<a.x<<endl;
}

      通过在成员函数中返回this指针,我们得到了指向这个对象本身的指针,并且可以通过它来改变对象。

      但是在很多情况中,我们更想用智能指针去控制对象的生存周期,比如这样。

int main (void) 
{
	shared_ptr<A>sp1(new A());
	shared_ptr<A>sp2(sp1->getthis());
	cout<<sp1.use_count()<<endl;
	cout<<sp2.use_count()<<endl;
}

      两个智能指针的引用计数都是1,可想而知在函数退出的时候会发生什么,同一块内存被释放了两次,程序崩溃是免不了的。原因是this是裸指针,我们这么操作和用同一个裸指针给两个智能指针赋值是一个意思。如果我们能返回一个智能指针,那么问题就解决了。这时我们可以使用shared_from_this这个模版类。

class A:public enable_shared_from_this<A>
{
public:
	A(int y=0):x(y){ }
	shared_ptr<A> getthis()
	{
		return shared_from_this();
	}
	int x;
};

这样上面那段程序的输出是两个2,两个智能指针都意识到自己指向的是同一片内存,引用计数正确的发挥作用,同一片内存只会被析构一次。

shared_from_this 使用注意事项

不能再构造函数中调用shared_from_this()

除此之外,shared_from_this还有一个需要注意的地方。你可以点开shared_from_this的源码看看,他返回了enable_shared_from_this中唯一的一个成员变量

mutable weak_ptr<_Ty> _Wptr;

而当我们再看这个类的构造函数,并没有对这个成员变量赋值。可想而知,如果这个变量始终没有被赋值,那么我们无法使用shared_from_this这个函数。

为了弄清楚这个变量什么时候被赋值,我一步一步的调试了下面这行代码,虽说只有一行,但是他真的做了很多事情。

shared_ptr <A> sp1(new A());

来看这条语句,它做了三件事情,第一件事情是构造enable_shared_from_this这个类,毕竟想要构造A就要先构造他的父类。

此时wptr没有被赋值。

第二件事情是构造A,此时wptr也没有被赋值。

第三件事情,构造sp1,令人想不到的是,构造sp1之后,属于类A的父类的wptr被赋值了

所以可想而知,如果没有这样一个sp1的出现,我们是无法使用shared_from_this的。所以才有了所说的“不能再构造函数中调用shared_from_this()”的说法,这个构造函数指的是A的构造函数,因为那个时候wptr还没有值,当然不能调用shared_from_this。

当然了,这样也是不行的。

int main (void) 
{
	A a;
	shared_ptr<A>sp(a.shared_from_this());
}
继承问题

在同一个继承体系中,不能同时出现多个enable_shared_from_this类。父类继承了enable之后,子类只能对shared_from_this()的返回值进行转型。也就是说把shared_ptr转换成shared_ptr,想做到这一点,你只能这么写

 return dynamic_pointer_cast<B>(shared_from_this());

如下代码验证:

namespace test_enable_shared_from_this{

    class Derived : public std::enable_shared_from_this<Derived>
    {
    public:
        void SetValue(int a)
        {
            _a = a;
        }
        int GetValue() const
        {
            return _a;
        }
    private:
        int _a;
    };

    class Derived1 : public Derived
    {
    private:
        int _b;
    };

}

调用代码如下:

int main()
{
    using namespace test_enable_shared_from_this;
    auto d1 = std::make_shared<Derived1>();
    auto obj = d1->shared_from_this();

    return 0;
}

在这里插入图片描述
发现问题没有?虽然d1和obj对象地址一样,但是对象内存包含的成员属性不同。d1有自身的属性成员变量,但是obj没有,只含有基类的属性成员变量。是不是shared_from_this返回的对象中只包含那些直接继承

std::enable_shared_from_this呢?我们用多继承验证下:

namespace test_enable_shared_from_this{

    class Derived : public std::enable_shared_from_this<Derived>
    {
    public:
        void SetValue(int a)
        {
            _a = a;
        }
        int GetValue() const
        {
            return _a;
        }
    private:
        int _a;
    };

    class Derived1 : public std::enable_shared_from_this<Derived1>
    {
    private:
        int _b;
    };

    class Derived2 : public Derived, public Derived1
    {
    private:
        int _c;
    };

}

int main()
{
    using namespace test_enable_shared_from_this;
    auto d2 = std::make_shared<Derived2>();
    auto obj = d2->shared_from_this();

    return 0;
}

在这里插入图片描述
直接提示执行不明确,这个很好理解,它不知道你究竟返回哪个子类std::shared_ptr。所以,继承类中不能存在多次继承std::enable_shared_from_this。哪个类继承的这个类,就返回这个类实例化的对象

参考

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一些常见的C++大厂面试题及其解答: 1. 什么是多态?如何实现多态? 多态是指同一种操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果。在C++中,实现多态有两种方式:虚函数和模板。 - 虚函数 在基类中定义虚函数,派生类可以重写该虚函数。当用基类指针或引用调用该虚函数时,实际调用的是派生类中的函数。这种方式称为动态多态。 - 模板 模板是一种编译期多态性,允许类型参数化。通过模板可以实现函数或类的通用性,同时保持代码的安全性和可读性。这种方式称为静态多态。 2. 什么是智能指针?如何使用智能指针智能指针是一种封装了指针的对象,可以自动管理内存,避免内存泄漏和空指针引用等问题。C++11中提供了三种智能指针:unique_ptr、shared_ptr和weak_ptr。 - unique_ptr unique_ptr是独占式智能指针,用于管理一个对象的内存。它不能被复制,只能通过移动语义转移所有权。当unique_ptr超出作用域或被显式删除时,它所管理的对象会被自动销毁。 - shared_ptr shared_ptr是共享式智能指针,多个shared_ptr可以共享同一个对象的内存,当最后一个shared_ptr被销毁时,才会释放内存。通过控制块来记录当前有多少个shared_ptr指向同一个对象。 - weak_ptr weak_ptr是弱引用智能指针,它可以用于解决shared_ptr的循环引用问题。weak_ptr不拥有对象的所有权,只是提供了一种安全的访问方式。 使用智能指针时需要注意避免循环引用和空指针引用等问题。 3. 什么是虚函数?虚函数有什么作用? 虚函数是一种动态绑定的函数,用于实现多态。在基类中定义虚函数,在派生类中可以重写该虚函数。当用基类指针或引用调用该虚函数时,实际调用的是派生类中的函数。 虚函数的作用在于实现多态,使得程序可以在运行时根据对象的实际类型来调用适当的函数。这样可以提高代码的灵活性和可扩展性。 4. 什么是纯虚函数?如何使用纯虚函数? 纯虚函数是一种没有实现的虚函数,在基类中定义纯虚函数,派生类必须重写该函数才能使用。纯虚函数用于定义接口,让派生类来实现具体的功能。 定义纯虚函数可以在函数声明后加上`=0`,如下所示: ```cpp virtual void func() = 0; ``` 使用纯虚函数可以强制规定派生类必须实现某些函数,从而实现多态和接口声明的功能。 5. 什么是模板?如何使用模板? 模板是一种泛型编程技术,通过参数化类型和函数来实现通用性。模板可以实现函数或类的通用性,同时保持代码的安全性和可读性。 在C++中,定义模板可以使用关键字template和typename或class。模板可以有多个参数,可以是类型参数或非类型参数。 模板的使用可以通过实例化来完成,即在模板名后加上具体的类型或值。例如: ```cpp template<typename T> void func(T arg) { ... } func<int>(5); ``` 6. 什么是STL?STL中包含哪些容器?如何使用STL容器? STL是标准模板库的缩写,是C++中的一个重要库,提供了一系列容器、算法和迭代器等工具,用于简化程序开发。 STL中包含以下容器: - 序列式容器:vector、list、deque、array、forward_list - 关联式容器:set、map、multiset、multimap、unordered_set、unordered_map、unordered_multiset、unordered_multimap - 容器适配器:stack、queue、priority_queue 使用STL容器可以通过头文件`<container>`和`<algorithm>`来实现。例如: ```cpp #include <vector> #include <algorithm> using namespace std; vector<int> vec = {1, 2, 3, 4, 5}; sort(vec.begin(), vec.end()); ``` 7. 什么是RAII?如何使用RAII? RAII是资源获取即初始化的缩写,是一种C++编程技术,用于自动管理资源的生命周期。RAII的核心思想是:在对象的构造函数中获取资源,在对象的析构函数中释放资源。 使用RAII可以避免资源泄漏和空指针引用等问题,提高代码的可读性和可靠性。一般情况下,RAII可以通过智能指针、文件句柄、锁等方式来实现。 例如,使用智能指针实现RAII可以如下所示: ```cpp class MyObj { public: MyObj() { ... } ~MyObj() { ... } }; void func() { unique_ptr<MyObj> ptr(new MyObj()); // ... } ``` 当`func()`函数执行完毕时,`ptr`指向的对象会被自动销毁,从而释放资源。 以上是一些常见的C++大厂面试题及其解答,希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值