C++11 一些关键字 ,C++11左值右值和移动构造

auto关键字

根据赋值表达式进行自动识别类型(不是c++11新的)

c语言当中auto int z = 123; ---->>> 变成局部自动变量 和局部变量作用一样

c++重新实现auto的作用 为了简化代码 遍历容器的时候用

vector<int> arr;
int y = 1;
auto iter = arr.begin()  //编译器根据右边的返回值进行赋值自动推导    编译期确定好的  
for(auto x : arr) {}  !!!
    
cout <<typeid(iter).name() << endl;
//判断是否是同一类型   在模板中作用大
typeid(y).hash_cose() == typeid(int).hash_code(); 


//不能用于定义函数参数影响重载    编译期的功能
void func(auto x, auto y) {}
func(1, 2); func(1.2, 1.2);

//不能定义数组
auto w[100] = {1};

//不能用于非静态成员变量的定义, 可以定义static变量
class Base {
public:
    //auto y = 1;
    static int x;
private:
};
auto Base::x = 123;


constexpr 和 const区别

告诉编译器在编译期变量的值是多少 编译期常量(要在编译期确认的常量)

const 运行期常量

#include
#include
using namespace std;

constexpr int f(int x) {
    return x * 2;
}

class A {
public:
    constexpr A(int x) {}
};
int main() {
    //区别
    int n;
    cin >> n;
    const int x = n + 123;  //  运行期常量
    constexpr int y = 123;// 编译器常量   如果加了n会报错
    constexpr int y2 = f(123);   //要在编译期确定所以函数要放回constexpr值
    const A a(123);
    constexpr A b(123);
   	//下面没体现区别
    /* 
    const int x = 123;
    constexpr int y = 123;
    *(const_cast(&x)) = 456;  
    *(const_cast(&y)) = 456;
    
    cout << *(&x) << endl;//   因为&号运行期的   绕开了编译期的编译器优化(编译器把123贴给了x)
    cout << *(&y) << endl;
    return 0;*/
}

nullptr 和 NULL

NULL 是一个long long 的0 代表空地址 函数重载传值的时候可能出错

nullptr 是一个Dn类 ,也代表空地址

void func(int  x) {
    cout << __PRETTY_FUNCTION__ << endl;
    cout << x << endl;
    return ;
}
void func(int *x) {
    cout << __PRETTY_FUNCTION__ << endl;
    cout << *x << endl;
    return ;
}

cout << NULL << endl;   // 0
cout << nullptr << endl;   // nullptr

右值

左值 右值 左值引用 右值引用 (右值绑定右值引用, 左值绑定左值引用)

如何判断是一个表达式是左值还是右值

到了下一行的时候看看是否能通过单一变量访问到值(能:左值 不能:右值)(一般产生临时变量的是右值) (字面量是右值)

#include
#include
using namespace std;
#define func(x) __func(x, "func("#x")")

void __func(int &x, const char *str) {
    cout << str << "is lest" << endl;
    return ;
}
void __func(int &&x, const char *str) {
    cout <<str <<"is right" << endl;
    return ;
}
class A {
public:
    A operator+(int x) {}
    A &operator+=(int x) {}
};

int main() {
    func(1234);//右值
    int x = 1234;
    int y = 1;
    func(x);//下一行可以用x访问到所以是左值
    func(x + y);//没有办法利用单一变量访问  是右值
    func(x++);//访问不到x加一之前的值  右值
    func(++x);// 可以用x访问到   左值
    func(x + 123);// 右
    func(x *= x);// 左
    func(y += 4);// 左
    func(y * 3);// 右

    return 0;
}

右值 — >>> 引出来右值引用 — >>> 右值是个临时变量 ---- >>> 移动构造(用右值引用接受临时变量)

move() 把一个值变成右值 , forward (x) 按你想的类型往下传递(可以是右值可以是左值)

move() 和 forward<>() 保证了正确的函数重载形式

#define func(x) __func(x, "func("#x")")
#define func2(x) __func2(x, "func2("#x")")

void __func2(int &x, const char *str) {
    cout << str << "is lest" << endl;
    return ;
}
void __func2(int &&x, const char *str) {
    cout <<str <<"is right" << endl;
    return ;
}
void __func(int &x, const char *str) {
    cout << str << "is lest" << endl;
    func2(x);   
    return ;
}
void __func(int &&x, const char *str) {
    cout <<str <<"is right" << endl;
    func2(forward<int &&> (x));
    //func2(move(x))  //强行变成右值
    //func2(x)   //如果这里不加move() 或者forward 方法   那就是变成   左值传递  
    return ;
}

移动构造

用右值引用接收右值 ,然后把右值的数据值拷贝给类 相当与在右值上修改指针指向或者修改名字。这样就不用遇到临时变量时利用拷贝构造进行深拷贝开辟空间构造一个匿名对象然后再进行赋值。 提高了效率。

没有移动构造的话, 只要产生拷贝行为那就一定是深拷贝。STL效率提升,

拷贝构造存在深拷贝就要有移动构造。

#include
#include
using namespace std;


namespace haizei {

class vector {
public:
    vector(int n = 10):__size(n), data(new int[n]) {
        cout << "default con" << endl;
    }
    //每次返回临时变量或产生拷贝行为都是深拷贝
    vector(const vector &v):__size(v.size()), data(new int[__size]) { 
        cout << "deep copy" <<endl;
        for (int i = 0; i < size(); i++) data[i] = v[i];
        return ;
    }
    //(v1 + v2) 返回一个临时变量 -- 一个匿名对象接受右值调用移动构造
    // v3(v1 +v2) 一个匿名对象也是临时变量   --  调用移动构造
    vector(vector &&v):__size(v.size()), data(v.data) {
        cout << "move con" << endl;
        v.data = nullptr;
        v.__size = 0;
    }
    vector operator+(const vector &v) {
        vector ret(v.size() + this->size());
        vector &now = *this;
        for (int i = 0; i < size(); i++) {
            ret[i] = now[i];
        }
        for (int i = size(); i <ret.size(); i++) {
            ret[i] = v[i - size()];
        }
        return ret;
    }
    int &operator[](int ind)const {
        return this->data[ind];
    }
    int size() const{
        return __size;
    }
private:
    int __size;
    int *data;
};
    
};
ostream &operator<<(ostream &out, const haizei::vector &v) {
    for (int i = 0; i < v.size(); i++) {
        out<< v[i] << " ";
    }
    return out;
}
void func(haizei::vector A) {
    cout << "11" << endl;
}

int main() {
    haizei::vector v1, v2;
    for (int i = 0; i < v1.size(); i++) v1[i] = rand() % 100;
    for (int i = 0; i < v2.size(); i++) v2[i] = rand() % 100;
    haizei::vector v3(v1 + v2);
    cout << v1 << endl;
    cout << v2 << endl; 
    cout << v3 << endl;
    haizei::vector v4(move(v1)); // 强制变成右值
    cout << v1 << endl;
    cout << v4 << endl;
    func(move(v1)); //把他变成右值传递调用移动构造  但是v1会消失了
}


绑定顺序

左绑左 右绑右 不管咋 先看const ( const type & 可以绑定任何数据)

优先绑定最匹配的

#include
#include
using namespace std;

void func1(int &x) {
    cout << __PRETTY_FUNCTION__ << " c" << endl;
}
void func1(const int &x) {
    cout << __PRETTY_FUNCTION__ << " c" << endl;
}
void func1(int &&x) {
    cout << __PRETTY_FUNCTION__ << " c" << endl;
}
void func1(const int &&x) {     //用的比较少
    cout << __PRETTY_FUNCTION__ << " c" << endl;
}

//ostream &operator<<(ostream &out, const A &);  因为const A&  可以接受任何值

int main() {
    int n;
    func1(n);//优先绑定到左值的版本上
    const int y = 123;
    func1(y); //  优先绑定const 左值
    func1(123 + 456); //优先绑定右值引用版本
    return 0;

}

你可能感兴趣的:(C++语法学习,c++)