#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <cassert>
#include <typeinfo>
using namespace std;
//C++11 右值引用和void std::move()函数
//右值:在 = 的右边,没名称,没法取地址,只是一个字面值或临时变量
//左值:在 = 的左边,有名称,可以取地址
////1. move只是将参数转为右值,本身并不会提升性能和改变原来的内容
//// 一般在某个对象或者数据需要放入容器,但不想再拷贝一份数据,使用move会提升性能
////2. 右值作为类的拷贝构造函数、赋值运算符的参数,可以不进行资源的深拷贝,
//// 直接将对象的指针拿过来并还原被拿者为初始状态,从而减少拷贝消耗的性能
//// (不懂,需要这样拷贝或者赋值,为啥不直接使用原来那个对象呢)
void testMove()
{
//str1有名称,可以取地址,是左值;“1234”无名称,无法取地址,是右值
string str1 = "1234";
vector<string> vec;
vec.push_back(str1);//复制一份放入容器
cout << str1 << endl;//普通左值,原来的数据还在
//vec.push_back(move(str1));//STL容器支持右值操作,不复制,直接将当前的数据放入容器
//并使当前的数据为初始状态,此时性能有所提升
string str2 = move(str1);//string的拷贝构造支持右值操作,str1内容将被拿走并初始状态
cout << str1 << endl;
}
//C++11 如果类中存在内存管理,需要自定义:
// 析构函数(防止资源泄漏)
// 拷贝构造函数(防止浅拷贝)
// 赋值运算符(同上)
// 右值拷贝
// 右值赋值
class MyClass
{
public:
//构造函数
MyClass(const char* str)
{
int len = strlen(str) + 1;
m_str = new char[len];
memset(m_str, 0, len);
memcpy_s(m_str, len - 1, str, len - 1);
cout << " is constructor :" << m_str << endl;
}
//拷贝构造函数
MyClass(const MyClass& l)
{
int len = l.getLen() + 1;
m_str = new char[len];
memset(m_str, 0, len);
memcpy_s(m_str, len - 1, l.getData(), len - 1);
cout << " is l copy constructor " << m_str << endl;
}
//右值拷贝(右值拷贝结束时,参数需要变成初始状态)
MyClass(MyClass&& r)
{
m_str = r.getData();
r.setData(nullptr);
cout << " is r copy constructor " << m_str << endl;
}
//赋值运算符
MyClass& operator = (const MyClass& m)
{
if (this == &m)
{//自赋值
return *this;
}
//释放原来的资源
if (m_str) delete m_str;
//创建空间,拷贝数据
int len = m.getLen() + 1;
m_str = new char[len];
memset(m_str, 0, len);
memcpy_s(m_str, len - 1, m.getData(), len - 1);
cout << " is l equal constructor " << m_str << endl;
return *this;
}
//右值赋值运算符
MyClass& operator = (MyClass&& m)
{
if (this == &m)
{//自赋值
return *this;
}
int len = m.getLen() + 1;
m_str = new char[len];
memset(m_str, 0, len);
memcpy_s(m_str, len - 1, m.getData(), len - 1);
m.setData(nullptr);
cout << " is r equal constructor " << m_str << endl;
return *this;
}
~MyClass()
{
if(m_str)
delete m_str;
}
public:
int getLen() const { return strlen(m_str); }
char *getData() const
{
assert(m_str);
return m_str;
}
void setData(const char* str)
{
if (str == nullptr)
{//右值拷贝的时候,直接改值,不要释放资源
m_str = nullptr;
return;
}
delete m_str;
int len = strlen(str) + 1;
m_str = new char[len];
memset(m_str, 0, len);
memcpy_s(m_str, len - 1, str, len - 1);
};
private:
char *m_str = nullptr;
};
void testClass()
{
MyClass m("1234");//构造
MyClass a = m;//拷贝构造
MyClass n = move(m);//右值拷贝构造
//cout << m.getData() << endl;//error m 被右值后资源被初始化,不能再访问资源
m = a;//赋值运算符
n = move(a);//右值赋值运算符
}
//C++11 类型推导结合使模板的定义和使用更加简单
template<typename A, typename B>
auto add(A a, B b) -> decltype(a + b)
{
return a + b;
}
//错误,此时的a和b还未定义decltype(a + b)无法推导
//template<typename A, typename B>
//decltype(a + b) add(A a, B b)
//{
// return a + b;
//}
void testAuto()
{
//C++11 类型推导
//auto 类型推导必须定义时就初始化
auto a = char('a');//auto = char
cout << a << " " << typeid(a).name() << endl;
auto b = 'b';//auto = char
cout << b << " " << typeid(b).name() << endl;
auto c = "c";//auto = const char *
cout << c << " " << typeid(c).name() << endl;
auto d = const_cast<char *>("d");//auto = char *
cout << d << " " << typeid(d).name() << endl;
auto e = string("e");//std::string
cout << e << " " << typeid(e).name() << endl;
auto f = 102;//auto = int
cout << (char)f << " " << typeid(f).name() << endl;
//decltype 类型推导的表达式中的数据必须是已定义的
decltype(f) g;
g = 103;
cout << (char)g << " " << typeid(g).name() << endl;
auto h = new int(104);
cout << (char)*h << " " << typeid(h).name() << endl;
auto i = add(1.01, 2.0);
cout << "i = " << i << " " << typeid(i).name() << endl;
}
//C++11 范围for循环
void testFor()
{
int array[10] = { 0,1,2,3,4,5,6,7,8,9 };
//旧的访问方式,用下标以引用的方式访问数组
for (int i = 0; i < sizeof(array) / sizeof(int); ++i)
{
cout << array[i] << " ";
}
cout << endl << "******************************************" << endl;
//C++11
for (auto i : array)
{//按值访问,容器内的数据不会被修改,但是每个元素都会被临时创建,影响性能
cout << i << " ";
}
cout << endl << "******************************************" << endl;
for (auto& i : array)
{//按引用访问,不会创建临时对象,但容器内的数据可以被修改
cout << i << " ";
}
cout << endl << "******************************************" << endl;
for (const auto& i : array)
{//按const引用访问,不会创建临时对象,容器内的数据也不可以被修改
cout << i << " ";
}
cout << endl << "******************************************" << endl;
}
int main()
{
// testMove();
// testClass();
// testAuto();
testFor();
getchar();
return 0;
}
C++11学习笔记 -- move、auto、decltype、for
最新推荐文章于 2024-09-19 15:42:13 发布