C++ 需要注意的知识点

1. #ifndef 和 #program once的区别

2. #include <> 和 “ ” 的区别

3. 无符号和有符号都有1、2、4字节的结构,什么时候用无符号数?什么时候用有符号数?

4. #pragma pack(push,packing)  #pragma pack(pop,packing)

#pragma pack(1) 

#include <winsock2.h>  #pragma comment(lib,"ws2_32")

5. typedef 和 #define 的区别

6. 不同文件里包含同一命名空间

7. WSASocket 与 Socket 区别?

 8. memset 和 malloc 使用区别?

9. malloc free 和 new delete 的区别?

new 与 malloc 的区别在于,new在分配完内存之后会调用构造函数。

10. 深拷贝浅拷贝的区别?

主要区别在于内存是否独立

  • 浅拷贝:只复制了指针地址 → 两个对象指向同一块资源,容易二次释放、悬挂指针

  • 深拷贝:复制对象时,分配新内存,再拷贝指针指向的数据 → 对象互相独立,销毁时不会互相影响

什么时候用深拷贝?拷贝指针的时候,B浅拷贝A,如果A被释放了,那么再调用B就会崩溃。需要深拷贝重新给B申请一块内存。

拷贝构造移动构造 的区别?

关键区别:左值(拷贝构造)还是右值(移动构造)去初始化对象

  • 左值:有名字、能取地址、能在“=”号左边出现的对象。
  • 右值:临时对象、字面量、std::move 之后的东西
  • 拷贝构造:用一个已经存在的对象去初始化另一个正在创建的对象           复制 → 可能是浅拷贝或深拷贝。

    • 语法特征
      • ClassName(const ClassName& other)
    • 触发时机
      • ClassName b = a;
      • func(ClassName obj) 参数按值传递
      • ClassName retVal func() 函数返回值

    (区别于拷贝赋值运算符:ClassName& operator=(const ClassName& other);   a = b;

                把一个已经存在的对象 赋值给 另一个已经存在的对象)

  • 移动构造:用临时对象去初始化新对象                   转移 → 偷资源,原对象清空。

    • 语法特征:MyClass a(); MyClass b = a();

附加题:区分默认构造、拷贝构造、移动构造、拷贝赋值、移动赋值

凡是“新生对象”就是构造;只有“已有对象被覆盖”才是赋值。

const 会“冻结”移动,只能回落到拷贝

分析以下代码每个步骤属于什么构造:

Foo a;                                                              默认构造
Foo b{};                                                            默认构造 C11 统一初始化

Foo a(42);                                                          带参构造
Foo b = Foo(42);                                                    带参构造

Foo a; Foo c
= a; a有名字、有地址、可以出现在等号左边 Foo c(a); 拷贝构造 Foo d = std::move(a); 移动构造 Foo a, b; b = a; 拷贝赋值 b = std::move(a); 移动赋值 void func(Foo x); Foo a; func(a); 拷贝构造 func(std::move(a)); 移动构造 std::vector<Foo> v; v.push_back(Foo()); Foo()是临时对象,移动构造 v.push_back(a); 拷贝构造(虽然v已经存在了,
但里面的元素还不存在。push_back是将已经存在的a值拷贝到新创建的元素)

 Foo make() {
  Foo x;
  return x; 
  }                                                       C17编译器会优化直接就地构造,没有拷贝/移动
  Foo a = make();                                           未优化,因为返回的临时值 所以是 移动构造

  std::vector<Foo> v;
  v.emplace_back();                                             无参构造,会直接默认构造一个Foo()

11. const 加载函数前后的区别?

12. 指针的引用是什么?有什么用?

13. 用char数组千万记得加结束符'\0',否则会乱码。

14. 容易造成内存溢出的函数:

  • strcpy:会将字符串复制到缓冲区,建议使用strncpy()
  • strcat:会将字符串合并到缓冲区末尾,建议使用strncat()
  • sprintf():跟strcpy一样
  • scanf()系列

15. 避免 “野指针” “悬空指针”

野指针:不知道指向了什么地址的指针,比如指针声明时没有初始化:FILE* file; file指向什么值取决于栈上的随机内容, 此时

if (file) fclose(file); 因为file确实指向了一个随机地址是非空的,此时会关闭一个莫名其妙的地址,造成崩溃。记住指针声明时必须初始化:

FILE* file = nullptr;

悬空指针:指针指向的内存已经被释放了,但是指针没有置空。如果后面不小心再次使用了该指针,就会产生未定义错误。

16. NULL nullptr 的区别

17. const char*string 的区别

一个是C风格字符串,一个是C++风格字符串。

string自动管理内存,使用更安全。

string 转 const char* 调用 .c_str()

const char* 转 string 调用 

18. perror throw 两种报错方式的区别

perror 打印出错信息到 stderr,然后程序继续跑。缺点是错误没办法往调用栈上传递,调用者必须依赖打印。

throw 把错误作为异常抛出,调用者可以选择捕获或不捕获。好处是异常安全,能优雅地传递错误信息,不和日志输出耦合。还能带自定义上下文。

posted @ 2022-07-04 14:50  番茄玛丽  阅读(39)  评论(0)    收藏  举报