上来直接问C++11新特性,我说了智能指针,然后让我手写shared_ptr,我说不太会。。然后让我手写string。。
C++
1. C++11新特性有哪些?
- auto & decltype 关键字 在编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚地知道表达式的类型,然而要做到这一点并非那么容易,为了解决这个问题,C++11引入了auto类型说明符,它能让编译器替我们去分析表达式所属的类型。即auto让编译器通过初始值来推算变量的类型,所以auto定义的变量必须有初值。
// 由va1 和 va2 相加的结果可以推断出item的类型
auto item = va1 + va2; // item初始化为va1和va2相加的结果
有时候还会遇到这种情况:希望从表达式的类型推断出要定义的变量的类型,但是不想用该表达式的值初始化变量。为此,C++11 引入了第二种类型说明符decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值:
decltype(f()) sum = x; // sum的类型就是函数f的返回类型
编译器并不实际调用函数f,而是使用当调用发生时f的返回值类型作为sum的类型。
decltype处理顶层const和引用的方式与auto有些许不同。如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内)
const int ci = 0, &cj = ci;
decltype(ci) x = 0; // x的类型是const int
decltype(cj) y = x; // y的类型是const int&,y绑定到变量x
decltype(cj) z; // 错误!z是一个引用,必须初始化
-
右值引用、move函数、完美转发:可以见juejin.cn/post/703394…
-
新特性还有智能指针、范围for循环、lambda表达式等等。。。
2. 聊聊智能指针
3. 实现shared_ptr
// 暂时未考虑线程安全问题
template <typename T> class shared_ptr {
public:
shared_ptr(T* p) : count(new int(1)), ptr(p) {} // 构造函数
shared_ptr(const shared_ptr<T>& p) : count(p.count), ptr(p.ptr) { // 拷贝构造
(*count)++;
}
shared_ptr<T>& operator=(const shared_ptr<T>& p); // 拷贝赋值运算符
T* operator->() { return ptr; }
T& operator*() {return *ptr; }
~shared_ptr() {
if(--(*count) == 0) {
delete count;
delete ptr;
}
}
private:
int* count; // 实现计数机制
T* ptr;
};
template <typename T> shared_ptr<T>& shared_ptr<T>::operator=(const shared_ptr<T>& p) {
if(this != &p) { // 注意这里的写法,防止自我赋值
if(--(*count) == 0) {
delete ptr;
delete count;
}
ptr = p.ptr;
count = p.count;
++(*count);
}
return *this;
}
4. 实现string
#include<cstring>
class string {
public:
string(const char* ch = nullptr);
string(const string& s); // 拷贝构造函数(需要进行深复制)
string& operator=(const string& s); // 拷贝赋值运算符
string operator+(const string& s);
string& operator+=(const string& s);
int size() { return len; }
~string() {
delete[] str;
}
private:
char* str;
int len; // 字符串长度
};
string::string(const char* ch) {
if(!ch) {
len = 0;
str = new char[1];
str[0] = '\0';
}
else {
len = strlen(ch); // 传入strlen的指针必须指向以 空字符 作为结束的数组,但是它记录的长度不包括空字符
str = new char[len + 1];
strcpy(str, ch);
}
}
string::string(const string& s) {
len = s.len;
str = new char[len + 1];
strcpy(str, s.str);
}
string& string::operator=(const string& s) {
if(this != &s) {
delete[] str;
len = s.len;
str = new char[len + 1];
strcpy(str, s.str);
}
return *this;
}
string string::operator+(const string& s) {
string newstring;
newstring.len = len + s.len;
newstring.str = new char[newstring.len + 1];
strcpy(newstring.str, str);
strcat(newstring.str, s.str);
return newstring;
}
string& string::operator+=(const string& s) {
len += s.len;
char* newstr = new char[len + 1];
strcpy(newstr, str);
strcat(newstr, s.str);
delete[] str;
str = newstr;
return *this;
}
操作系统
1. 怎么处理多线程冲突?
当多个线程或进程同时处理一个文件/数据而发生冲突时,可以通过加锁或解锁来解决,或者规定它们的优先级。