目录
一、std::string是深拷贝还是浅拷贝,深拷贝与浅拷贝的区别
二、string、vector等容器中,size和capacity的区别
一、std::string是深拷贝还是浅拷贝,深拷贝与浅拷贝的区别
std::string是深拷贝。
对于普通变量,深拷贝和浅拷贝没有区别,都是复制一份;
关键在于引用、指针,浅拷贝只是复制了指针对象,并未拷贝指针指向的实体,因此拷贝前和拷贝后的两个对象拥有同一份指针指向的实体,或者说内存空间,任一方的修改都会同步影响另一方,还会有重复delete的风险;而深拷贝不仅复制指针对象,还会开辟新的内存空间,将指针指向的实体完整复制一份,这样使得拷贝前后的对象完全独立,互不影响,且没有重复delete的风险;
涉及到引用、指针时,一般要考虑使用深拷贝。
二、string、vector等容器中,size和capacity的区别
capacity是预留了多少个元素的内存空间,size是实际填充了几个元素;如vector的reserve()方法会置capacity个预留空间,size()返回实际push_back()了的元素数量;reserve()方法只开辟空间不初始化,resize()可初始化。
通常resize()不改变capacity只改变size,但如果resize()的大小大于当前capacity,则会改变capacity。
resize()只改变受影响部分的值,不改变被保留部分的值;比如已有三个元素a、b、c,现在执行resize(1, 'x');,执行完将只剩一个元素,但值并不修改为x而是保留a。
三、vector和list的区别、map和set的区别
vector是连续内存空间,list不连续是用链表实现的;
随机存取多用vector,添加删除多用list;
List不支持随机访问,无[]、at()。
/*------------------------------------------------------------------------------------*/
map用红黑树实现,key和value不同,默认有序;
set用红黑树实现,key和value相同,默认有序;
有序是因为RB-tree是有序的;
map可以修改value但不可修改key,set因key和value相同所以都不能修改;修改key会因为底层是RB-tree而导致错乱;
unorder_map用哈希表实现,默认无序。
四、STL中的关联容器与序列容器
map、set是关联容器,通过key-value来访问;
vector、list、deque是序列容器。
五、迭代器失效问题
- vector、deque迭代器要接收erase()的返回值,即iter=erase(iter);
- map、set的erase()返回void因此无需接收,用erase(iter++);方式防止用了失效迭代器;
- list两种方式兼备。
end()是最后一个元素的再后一个。
六、用过C++11哪些新特性
语言级的线程支持、lambda表达式、新的空指针nullptr、自动类型推导auto、for&&auto对for()循环的优化/基于范围的for()循环、列表初始化、解决双右尖括号与右移运算符的歧义。
像智能指针、右值引用、move()什么的实际写过的代码较少。
七、auto_ptr、unique_ptr、shared_ptr、weak_ptr
- auto_ptr未对对象所有权的转移加保护,即未删除=赋值构造,会出现指针重复释放的bug,导致运行期崩溃;
- unique_ptr以删除=赋值语句在语法上保证了对象的独占性,但这种限制也失去了灵活性,同时仍存在auto_ptr的重复释放bug,因为unique_ptr<int> pp(a_int_pointer)这种拷贝构造语法写多句仍然合法;
shared_ptr采用引用计数的方式使得一个对象可以由多个shared_ptr包装,解决了重复包装的问题,但存在循环引用时无法析构导致卡死的问题;
weak_ptr专为解决shared_ptr循环引用的问题而生,不增加引用计数,具体使用方法是把其中一个shared_ptr改为weak_ptr。
make_shared一次性申请内存效率更高,而且对RAII的机制保护的更好:
(101条消息) C++中用make_shared创建对象和直接定义shared_ptr有什么区别。_std::make_shared创建对象_彪莫婆婆的博客-CSDN博客
八、shared_ptr的线程安全问题
shared_ptr本身是线程安全的,引用计数的增减采用了原子机制;但不保证其包装的对象的线程安全性,多线程地对其包装对象的读写需要编程者自行加入互斥机制保证线程安全。
九、C++的内存管理
堆:new、malloc动态申请的内存空间,手动申请、手动释放,虽有内存泄露风险,但程序结束后操作系统仍会收回;
栈:函数的局部变量、形参、返回值,编译器自动分配、自动释放,效率高;
全局/静态存储区:全局变量、static
常量存储区:常量const
十、堆和栈的比较
- 栈由编译器自动管理,无需程序员介入;堆由程序员管理,容易内存泄露;
- 栈的可用空间一般比堆小,但可以在系统设置中修改;
- 堆上频繁new/delete造成内存碎片,栈是压栈弹栈即先入后出的方式,无内存碎片问题;
- 生长方向不同,栈向下生长,堆向上生长;
- 栈的分配效率比堆高,因为栈是计算机底层用专门的寄存器提供支持的,有专门的压栈出栈指令;堆是C++库提供的,要额外执行一套搜寻、申请内存的算法,效率相对较低。