吾乃修魔
无情无泪
跟风作对
与天挣命
下得九幽
上可三清
怒断黄泉
笑斩万邪
踏破苍天
卧劈神佛
癫瑕代替了我那不流在南山路上,也不留在雷锋塔下的泪。希望我永远都是你心内的阳光!
3 月 27
癫瑕代替了我那不流在南山路上,也不留在雷锋塔下的泪。希望我永远都是你心内的阳光!
9 月 29
主要是为了解决C++中NULL带来的二义性问题(因为NULL的值实际是0)
使用auto进行类型的自动推导可以大大简化编程工作;auto是在编译期执行,所以不会影响程序运行速度;由于C++编译的特性是从右向左推断类型,所以不会影响编译速度。
//auto的使用示例 //auto tmp; // 错误,auto是通过初始化表达式进行类型推导,如果没有初始化表达式,就无法确定tmp的类型 auto tmp = 1;//等价于int tmp = 1; auto tmp = 1.0; //等价于 double tmp = 1.0; auto tmp = "Hello World"; //等价于 char *tmp = "Hello World"; auto tmp = 'A'; //等价于 char tmp = 'A'; auto func = less<int>(); vector<int> arr; auto it = arr.begin(); //等价于vector<int>::iterator it = arr.begin(); auto p = new foo(); // 对自定义类型进行类型推导
另外auto可以应用于模版:
//auto应用于模版
//1.不使用auto
template <class Student, class Teacher>
void levelUp(const Teacher& th)
{
Student * addSalary = th.levelPlus();
// do somthing with addSalary
}
//2.使用auto
template <class Teacher>
void levelUp(const Teacher& th)
{
auto * addSalary = th.levelPlus();
// do somthing with addSalary
}
//使用decltype()得到变量类型
int x = 3;
decltype(x) y = x;
template <class Teacher>
void levelUp(const Teacher& th)->decltype(th.levelPlus();)
{
auto * addSalary = th.levelPlus();
// do somthing with addSalary
}
为了避免手动编写空默认构造函数,C++11引入了显示默认构造函数的概念,从而仅仅需在类的定义中编写空默认构造函数而不须要在实现文件里提供事实上现,相同的,C++还支持显式删除构造函数的概念。
//默认构造函数和删除 启用默认构造函数A()=default; 删除默认构造函数A()=delete;
lambda表达式类似Javascript中的闭包,它可以用于创建并定义匿名的函数对象,以简化编程工作。
Lambda语法:[函数对象参数](操作符重载函数参数)->返回值类型{函数体}
//lambda表达式
vector<int> arr{5, 4, 3, 2, 1};
int a = 2, b = 1;
for_each(arr.begin(), arr.end(), [b](int &x){cout<<(x + b)<<endl;});
//b就是指函数可以得到在Lambda表达式外的全局变量
for_each(arr.begin(), arr.end(), [=](int &x){x *= (a + b);});
//在[]中传入=的话,即是可以取得所有的外部变量
for_each(arr.begin(), arr.end(), [=](int &x)->int{return x * (a + b);});
//①[]内的参数指的是Lambda表达式可以取得的全局变量
//②()内的参数是每次调用函数时传入的参数
//③->后接的是Lambda表达式返回值的类型
详见:https://x.wolfmark.org/x-select_2018-09-10_481.html
(中第23②)
因为函数在参数传递(实参—>形参)的时候会有两种形式:值传递和引用传递。若使用值传递,在遇到大的对象作为参数时会耗费大量时间与内存空间。采用引用就不会有这个拷贝过程。所以使用引用。而我们一般又希望作为参数的引用不要改变原来的对象的内容,所以采用常量引用(const &)。
拷贝构造函数,首先是一个函数,其次它的任务就是借用一个本类型的对象,拷贝创建一个新的对象。
所以有如下的过程:实参—>形参—>新创建的对象
其中,形参—>新创建的对象,是拷贝构造函数这个函数所赋予的功能(新创建的对象要和作为参数的对象内容相同但是拥有独立的内存空间)。
类的构造函数是没有返回值的,所以实参—>形参之后,还是需要一个形参—>拷贝初始化新对象的过程。
首先还是为了不拷贝大对象,所以使用引用。
但是由于引用对象是右值(如字面值或者临时对象),因为这类值本身就是用于临时存储,所以窃取其值不影响程序正确性。
所以这样我们如果确实需要一个单独的传入的参数也不需要拷贝了,就直接将这个传入的参数“据为己有”即可。
总结:移动构造函数就是实参—>形参,形参—>新创建的对象,这两个过程的拷贝都省了。
//(1)声明一个右值引用
int&& i = 42;
或者
class X
{
private:
int* data;
public:X():data(new int[1000000]){}~X(){delete [] data;}
X(const X& other):data(new int[1000000]){std::copy(other.data,other.data+1000000,data);}
//拷贝构造函数
X(X&& other):data(other.data){other.data=nullptr;}};
//移动构造函数
//(2)使用在拷贝构造函数
X x1;
X x2 = std::move(x1);
X x3 = static_cast<X&&>(x2);
//(3)使用在函数模板
//填入左值,推断为左值引用;填入右值,推断为普通无修饰类型。
foo(42);foo(3.14159);foo(std::string());
//填入右值,推断为普通无修饰类型情况
int i=42;foo(i);
//填入左值,推断为左值引用情况
//初始化列表(更加优雅的初始化方法)
//引入C++11之前,只有数组能使用初始化列表,
//其他容器想要使用初始化列表,只能用以下方法:
int arr[3] = {1, 2, 3}
vector<int> arr(arr, arr + 3);
//C++11中,我们可以使用以下语法来进行替换:
int arr[3]{1, 2, 3};
vector<int> arr{1, 2, 3};
map<int, string>{{1, "a"}, {2, "b"}};
string str{"Hello World"};
//加长参数模板
//在C语言中printf可以传入多个参数,在C++11中,
//可以用加长参数模板实现更简洁的Print
template<typename head, typename... tail>
void Print(Head head, typename... tail) {
cout<< head <<endl;
Print(tail...);
}
//C++中的pair可以使用make_pair构造,构造一个包含两种不同类型的数据的容器
auto p = make_pair(1, "C++ 11");
//C++11中引入了变长参数模板(参见8),所以发明了新的数据类型:tuple
//tuple是一个N元组,可以传入1个, 2个甚至多个不同类型的数据
auto t1 = make_tuple(1, 2.0, "C++ 11");
auto t2 = make_tuple(1, 2.0, "C++ 11", {1, 0, 2});
//C++中for循环可以使用类似java的简化的for循环,
//可以用于遍历数组,容器,string以及由begin和end函数定义的序列
map<string, int> m{{"a", 1}, {"b", 2}, {"c", 3}};
for (auto p : m){
cout<<p.first<<" : "<<p.second<<endl;
}
c++11部分参考了文章:https://www.cnblogs.com/guxuanqing/p/6707824.html
//C++11要求Lambda参数使用具体的类型声明
auto lambda = [](int x, int y) {return x + y;};
//C++14的泛型Lambda使编写如下语句成为可能:
auto lambda = [](auto x, auto y) {return x + y;};
//新标准中的std::move函数可用于捕获Lambda表达式中的变量,
//这是通过移动对象而非复制或引用对象实现的:
std::unique_ptr ptr(new int(10));
auto lambda = [value = std::move(ptr)] {return *value;};
在C++11中,使用constexpr声明的函数可以在编译时执行,生成一个值,用在需要常量表达式的地方,比如作为初始化模板的整形参数。C++11的constexpr函数只能包含一个表达式,C++14放松了这些限制,支持诸如if 和switch等条件语句,支持循环,其中包括基于区间(range)的for 循环。
①如果一个函数的实现中有多个返回语句,这些语句一定要推导出同样的类型。
②返回类型推导可以用在前向声明中,但是在使用它们之前,翻译单元中必须能够得到函数定义。
③返回类型推导可以用在递归函数中,但是递归调用必须以至少一个返回语句作为先导,以便编译器推导出返回类型。
9 月 17
除此之外还有两个讲基础知识的博客推荐给大家:
1.https://github.com/CyC2018/CS-Notes
2.https://github.com/linw7/Skill-Tree
3.一个linux内核相关的项目TKeed:
https://github.com/linw7/TKeed
9 月 10
(由修根据深信服等公司的流出面试题和各公司的面经总结)
本文地址:https://x.wolfmark.org/x-select_2018-09-10_481.html
| 类型 | 比特数 | 有效数字 | 数值范围 |
| float | 32 | 6~7 | -3.4*10(-38)~3.4*10(38) |
| double | 64 | 15~16 | -1.7*10(-308)~1.7*10(308) |
| long double | 128 | 18~19 | -1.2*10(-4932)~1.2*10(4932) |
buffer=(char*)malloc(i+1);
有两个需要注意的地方:
(1) 当定义的是常量指针,需要const两次( const char* const iVar = “C++”),第一个const是防止值被改变,第二个const防止地址被改变。
(2) 当定义到class内时,需要用static来修饰这个变量,防止出现多个实体。
try
{
double *ptr=new double[1000000];
}
catch(bad_alloc &memExp)
{
//失败以后,要么abort要么重分配
cerr<<memExp.what()<<endl;
}
double *ptr=new double[1000000]; if( 0 == ptr)
/*TestC.h*/
#ifndef TESTC_H
#define TESTC_H
#ifdef __cplusplus
extern "C"{
#endif
int add(int a , int b);
#ifdef __cplusplus
}
#endif
#endif
/*TestC.c*/
#include"TestC.h"
int add(int a , int b)
{
return(a+b);
}
/*TestC.cc*/
#include <iostream>
#include "TestC.h"
int main()
{
cout << add(2,5) << endl ;
return 0;
}
/* ADD.h */
#ifdef ADD_H
#define ADD_H
class ADD
{
public:
int add(int a, int b)
{
return(a+b);
}
};
#endif // ADD_H
//*将C++类封装为C函数文件
/*ADD.cc*/
#include "ADD.h"
extern "C" int add_cpp(int a , int b);
int add(int a , int b)
{
ADD tmp ;
return tmp.add(a,b);
}
//*实际调用C++代码的C文件
/* add.c */
extern int add_cpp(int a , int b);
int main()
{
cout << add_cpp(2,3) << endl;
return 0;
}
//A使用隐式转换implicit
class A
{
public:
A(int){}
A(int,int){}
operator bool const {return true;}
};
//B类型使用显式转换explicit
class B
{
public:
explicit B(int){}
explicit B(int,int){}
explicit operator bool const {return true;}
};
int main()
{
A a1 = 1 ; //OK,使用A::A(int)
A a2(2); //OK,使用A::A(int)
A a3{4,5};//OK,使用A::A(int,int);
A a4 ={4,5};//OK,使用A::A(int,int);
A a5 = (A)1;//OK,使用 static_cast
bool na1 = a1 ;//OK,复制构造函数使用 A::operator bool()
bool na2 = static_cast<bool>(a1);//OK 使用static_cast 直接赋值
B b1 = 1 ; //出错,不会使用B::B(int)
B b2(2); //OK,使用B::B(int)
B b3{4,5};//OK,使用B::B(int,int);
B b4 ={4,5};//出错,不会使用B::B(int,int);
B b5 = (B)1;//OK,使用 stbtic_cbst
bool nb1 = b1 ;//出错,不会使用 B::operbtor bool()
bool nb2 = stbtic_cbst<bool>(b1);//OK 使用stbtic_cbst 直接赋值
}
self & operator++();
self operator++(T);//T是类型名,如int
class T{
T(const T&) = delete; //禁用复制构造函数
T(T&&) = default; //启用默认的移动构造函数
};
class SingleSample
{
public:
static SingleSample * getInterface();
private:
SingleSample();
SingleSample(const SingleSample &);
SingleSample & operator=(const SingleSample &);
~SingleSample();
static SingleSample * interface ;
}
//初始化:
SingleSample * SingleSample::interface;
SingleSample * SingleSample::getInterface()
{
return interface;
}
详细内容:https://x.wolfmark.org/x-select_2018-09-29_497.html
由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。实际上,用sizeof来返回类型以及静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。
具体而言,当参数分别如下时,sizeof返回的值表示的含义如下:
数组——编译时分配的数组空间大小;
指针——存储该指针所用的空间大小(存储该指针的地址的长度,是长整型,应该为4);
类型——该类型所占的空间大小;
对象——对象的实际占用空间大小;
函数——函数的返回类型所占的空间大小。函数的返回类型不能是void。
char s[] ="hello";
char *p = s;
//注意 \0 不算在内
cout << strlen(s) << endl;//5
cout << strlen(p) << endl;//5
cout << sizeof(s) << endl;//6
cout << sizeof(p) << endl;//4
(由修根据深信服等公司的流出面试题和各公司的面经总结)
更多秋招知识请看-秋招总结-猿类面试小书:
7 月 22
注:大田赛归来,没有取得理想的成绩,却也在意料之中,更让我确信了长跑是一个需要时间来沉淀的运动。我总认为摇摆不定的心境是阻碍我稳步向前的最大障碍,凡世的条条框框只会让我断了向前的希望;人的梦想,如果不去做,难道要等到来生?化为灰烬,唯有磨炼己身至一副钢筋铁骨才能踏破这天空。
——————————脩于公元二零一八年七月二十二日夜
4 月 10
由于以前一直在linux服务端上使用mysql,今天在windows笔记本上装了下,顺便写下了过程:
(注:由于软件时境过迁,只保证2018.4.10日(今天)此方法可用,后续软件升级后可能也会有些许出入)
一、在Mysql官网下载Mmysql-5.7.21的ZIP文件(免安装文件)
下载链接为:https://dev.mysql.com/downloads/mysql/
找到你的系统对应的版本下载,比如这里我的是:mysql-5.7.21-winx64.zip
二、解压ZIP文件
比如解压至:D:/soft/ ,更改 mysql-5.7.21-winx64 文件夹名称为 mysql
三、配置环境变量
1、新建一个变量:MYSQL_HOME
变量值:D:/soft/mysql
2、修改path变量
添加一条记录:%MYSQL_HOME%/bin
四、在D:/soft/mysql目录下创建如下my.ini文件
[mysqld]
#绑定IPv4
bind-address = 0.0.0.0
# 设置mysql的安装目录,即你解压缩安装包的位置
basedir = D:/soft/mysql
# 设置mysql数据库的数据的存放目录
datadir = D:/soft/mysql/data
# 设置端口号
port = 3306
# 允许最大连接数
max_connections = 200
# 设置字符集为utf8
loose-default-character-set = utf8
# 开启查询缓存
explicit_defaults_for_timestamp = true
# windows下区分表名大小写(0:不区分,2区分(5.7版本))
lower_case_table_names=2
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
[client]
#设置客户端字符集
port=3306
default-character-set = utf8
[WinMySQLadmin]
Server = D:/soft/mysql/bin/mysqld.exe
skip-grant-tables
五、将mysql注册为Windows系统服务
1、使用管路员权限打开CMD(注意管理员权限),在CMD中进入mysql的解压目录
2、运行服务安装命令
mysqld install MySQL –defaults-file=”%MYSQL_HOME%\my.ini”
安装成功后会提示安装成功
备注:如果想要移除该服务,使用命令:mysqld -remove
六、启动mysql服务
1、启动服务命令为:net start mysql
2、此时会提示:
启动不了mysql服务,提示发送系统错误2:”系统找不到指定文件”
①首先打开注册表
win+r打开运行,输入regedit,打开注册表
②更改注册表:找到
HKEY_LOCAL_MACHINE
-SYSTEM
-CurrentControlSet
-services-mysql(服务名)
-ImagePath
更改原来的值(默认目录):”C:\Program Files\MySQL\MySQL Server 5.7\mysqld” –defaults-file=D:\soft\mysql\my.ini MySQL
为(安装目录):”D:\soft\mysql\bin\mysqld” –defaults-file=”D:\soft\mysql\mysql5.6.17\my.ini” mysql
2、打开管理工具 服务,找到MySQL服务。通过右键选择启动或者直接点击左边的启动来启动服务
创建命令:mysqld --initialize-insecure --user=mysql
七、修改root账号密码
刚安装完成时root账号默认密码为空,此时可以将密码修改为指定的密码。
打开数据库:mysql -uroot -p(提示 Enter password,直接回车,默认密码为空)
use mysql;
update mysql.user set authentication_string=password('123456') where user='root'
flush privileges;
quit;
密码修改完成后既可以使用新密码登录。
10 月 07
——————————脩于公元二零一七年十月七日
昨日,闲来无事,遂去闲游,不知欲至何处。想来来江南已一载有余,还未尝见石,曰:三生。石边冷清,遂取笛而鸣,然声涩难鸣,故名乱笛。三生石中上石恰生三枝,在石下向上望,中石上一怪客,仿若骷髅(也许便是传说中的精魂吧),仿佛可以洞穿人心。午间山下小寺边食一碗素面,恰过清泉,泉边一寺,寺内“教学楼”见所未见,笑叹“和尚也教学”。大寺庙宇香火不断,千年古刹意蕴犹存,不足方圆的三丈财神庙内求签之人之热切满溢。财神庙外却是那九百五十级让烦人望而却步的长路,浑身腥臭的“懒驴”驮着沙从山底运至山顶。
近期评论