各种阴间坑

目录

make的时候报错找不到链接库

一个取巧的办法是

LD_LIBRARY_PATH环境变量加上缺失的动态库路径

正常的办法是使用cmake链上

查找类型的时候,可能和类内的名称冲突导致编译失败

struct test {
  int map;
  void f(map<int,int> a)
}

这里的map会首先查找到int map导致编译失败

纯虚函数可以被实现,并且可以被子类调用

C++primer上面有。抽象类可以在cpp里面实现纯虚函数,子类可以调用这个函数,但是该抽象类依然不能被实例化

malloc(0)、realloc(0)

malloc(0)返回并不是null
realloc(0)返回是0

有符号右移是UB

...裂开.jpg...

很阴间,右值指针不能++,--,包括前置和后置

很阴间,出现在华子的考试题里面

数组指针初始化

using type = int (*)[10];
int tmp[10][10];
type a = tmp[0]; ok
int tmp[10];
type a = &tmp;  ok

多继承的时候调用特定函数

/*
	From XDU'mzb
*/
#include <bits/stdc++.h>
using namespace std;
class A {
	public:
		void func() {
			cout << "A" << endl;
		}
};
class B {
	private:
		bool func() const {
			cout << "B" << endl;
		}
};
class C : public A,public B {
	
};
int main () {
	C test;
	test.A::func();
	return 0;
}

c++虚函数重载的时候

除了协变的规则,注意const属性必须保持一致
否者虚函数会形成重载

linux内存映射,bus error

发生错误的原因是因为mmap不能去扩展一个内容为空的新文件,因为大小为0,所有本没有与之对应的合法的物理页,不能扩展。

用write往里面写个字符就行

完整场景

关于const&和性能

const&不一定能提高性能,因为解引用指针以及其他的因素会导致性能下降

关于对齐

对齐的原则是任何大小为K的对象的起始位置都是K的倍数

关于静态变量初始化,造成死循环

在对malloc函数进行动态库打桩的时候发现的

void* malloc(size_t size){
  static auto ___ = init();  // 其中init中有malloc操作
}

这里会引起一个死循环,因为___没有完成初始化,在此重入malloc的时候,依旧会进入init函数,形成死循环

这个好像是叫recursive_init_error

/*
---- From XDU's mzb
*/
//#include <boost/any.hpp>
//using namespace boost;
#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
int init(int (*test)()){
	return test();
}
int test(){
	static int ___ = init(test); 
	return 0;
}
int main()
  {
  	test();
	return 0;
}

0

0可以自动转为指针类型
在函数重载中,可能匹配到空函数指针参数

cout << func

输出一个bool值

模板函数指针

auto func = min;
低版本的编译器会罢工 unable to deduce 'auto' from 'min'
然后类带模板指针的时候,一定要严格对应模板函数的类型,否则很容易匹配错误

虚函数 + 默认参数

可以运行,按指针的类型寻找对应的函数填参数

/*
---- From XDU's mzb
*/
#include <bits/stdc++.h>
#include <boost/any.hpp>
using namespace std;
using ll = long long int;
struct base
  {
  	virtual void show(string rhs = "base")
  	  {
  	  	cout << "base = " << rhs << "\n";
		}
	virtual ~base(){}
  };
struct sub : base
  {
  	virtual void show(string rhs = "sub")
  	  {
  	  	cout << "sub = " << rhs << "\n";
		}
  	virtual ~sub(){}
  };
int main()
  {
  	base * a = new sub();
  	sub * b = new sub();
  	a -> show();
  	b -> show();
  	
	return 0;
}

shared_ptr

f(shared_ptr<string>(new string()),
  shared_ptr<string>(new string()));
如果第二个new抛出异常,第一个new出来的内存不会被释放,正确的做法是使用**make_shared**

lambda捕获成员变量的问题

会捕获this,然后相当于引用捕获成员变量...没有一点报错或者警告

/*
---- From XDU's mzb
*/
#include <bits/stdc++.h>
#include <boost/any.hpp>
using namespace std;
using namespace boost;
using ll = long long int;
struct my
  {
  	ll data;
  	my()
  	  :data(0)
  	    {}
  	void f()
  	  {
  	  	auto lambda = 
  	  		[=]()
  	  		  {
  	  		  	//  这里捕获了this 
  	  		  	data++;
  	  		  	// this -> data++;
				  };
		lambda();
		cout << "data = " << data << endl;
		}
  };
int main()
  {
  	my().f();
	return 0;
}

ostream打开失败

在dll里面,ofstream.open需要使用绝对路径,相对路径会失败,很奇怪,错误码 5
可以用GetLastError得到最后一次的错误码

st表

st表的跳转可能需要把整个表刷出来
默认的st表是不需要全部刷出来的,但是在某些很特殊的情况下,是需要全部刷出来的
看情况

LoadLibrary加载不出来

const char dll_name[] = "E:\\InjectDll\\Inject_dll_test.dll";
需要双斜杠,路径单斜杠会GG,GetLAstError返回126(无法找到指定模块)

devc++下静态调用dll

不支持#pragam comment(lib,"dll")
需要从菜单 -> 项目属性 -> 链接 -> 添加库或者对象导入
好像导入.dll或者.a(也就是.lib文件)中的一个就行了
一个都不导入会出问题

c++数值最值

#include <limits>
cout << numeric_limits<int>::max() << endl;

宏可以转发参数

学到了.jpg

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
void f(ll n)
  {
  	cout << "f" << n << endl;
  }
void g(ll n)
  {
  	cout << "g" << n << endl;
  }
#define f(x,y,z) g(x)
int main()
  {
  	f(10,12,23);
	return 0;
  }

memcpy和memmove的区别

源和目标不重叠的时候两个函数没区别
源和目标重叠的时候,memmove保证结果正确

memmove用于从src拷贝count个字节到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。但复制后src内容会被更改。但是当目标区域与源区域没有重叠则和memcpy函数功能相同。

c++与动态链接库

c++函数导出的时候,会重整函数名,也就是函数名会变的非常阴间
用c方式导出好很多
dll导出对象的时候,有很复杂的问题

内存对齐

跨编译器/平台交互的时候一定要注意内存对齐的情况
c++ #pragma pack(x)
windows默认最小对齐x为4字节

std::conditional不是惰性求值

可以通过加壳的方式实现一个惰性求值的conditional

template<template<typename...> class op,typename ...Args>   // 惰性求值 
struct late_op
  {
  	using type = typename op<Args...>::result;
  };

然后调用std::conditional<0,xxx,xxx>::type::type即可,Stack Overflow中提供的思路,很巧妙
很多难题都可以通过增加一个间接层来实现

const

const 与 指针

int * p; //指向变量,指针可赋值
const int * p; //指向常量,指针可赋值
int const * p; //指向常量,指针可赋值
const int * const p; // 指向常量,指针不可赋值

const 和 构造函数

非 explicit 可能触发构造函数

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct node
  {
  	ll val;
  	node(ll val)
  	  :val(val)
  	    {}
  };
void f(node const& rhs)
  {
  	cout << rhs.val << "\n";
  }
int main()
  {
  	f(5);
	return 0;
  }
const 与 类
1.const可以触发const成员函数重载

必要的时候需要const_cast来调用重载函数

2.const成员函数可以修改非const的static成员
3.可以用mutable来修饰需要修改的常量对象中的成员
4.当const成员函数和非const成员函数差不多

可以用const_cast简化代码

c++ 默默的编写了哪些函数

1.默认构造函数
2.默认析构函数
3.默认拷贝构造函数
4.默认赋值运算符
5.取地址运算符
6.const的取地址运算符
取地址这个知识比较阴间...我也是偶然知晓

struct Empty
  {
    Empty();
	~Empty();
	Empty(const Empty&);
	Empty& operate = (const Empty&);
	Empty* operate & ();
	const Empty* operate&() const;
};

异常

1.析构函数不能也不应该抛出异常

如果释放资源可能抛出异常,写个普通函数处理

2.绝不要再构造,析构的时候调用虚函数

构造析构的时候,调用虚函数等效于调用父类的虚函数
因为此时类型是基类类型
包括typeid显示的是基类类型

3.成员swap不应该抛出异常

全局swap可能抛出异常

成员变量应该为private

proctected并不比public更具封装性
该用final用final

C++对象中数据成员的初始化顺序为其在类中声明的顺序,而不是成员初始化列表中的顺序

尽量保持生命顺序和初始化顺序一致

const成员函数可以修改static成员

构造函数可能抛出异常

这个处理比较复杂,后面补

析构函数不应该抛出异常

标准库的析构函数都不抛出异常

可变参数宏

... + __VA_ARGS__比较阴间,以后全部采用下面这种形式

/*
---- Author : XDU_mzb 
---- lisp 2.0
*/ 
#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
ll f(ll a,ll b,ll c)
  {
  	return a + b + c;
  }
#define add1(args...) f(1,2,##args)
#define add2(args...) f(args)
int main()
  {
  	cout << add1(3) << endl;
  	cout << add2(1,2,3) << endl; 
	return 0;
  }

c++存储空间

堆、栈、自由存储区、全局/静态存储区、常量存储区
自由存储区就是new出来的空间
堆就是malloca出来的空间
很多情况下,operator new的全局实现就是malloca
但是,可以通过存在operator new,改变new的实现
所以自由存储区和堆是两个概念,标准中未说明

const& 等效于右值

可能触发构造函数

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct test
  {
  	test(ll val)
  	  {
  	  	cout << "con" << endl;
		}
	~test()
	  {
	  	cout << "des" << endl;
	  }
  };
void f(test const& a) {}
int main()
  {
  	f(2);
	return 0;
  }

顶层const 与底层const

char s[] = "1231221";
const char  * a = s;
char * const b = s;
const char * const c = s;

以 * 为界
const char *a,a = xxx ok,a[0] = xx 错
char * const b,b = xxx 错,b[0] = xx ok

free,delete什么时候会导致程序崩溃

接上一条,delet的底层实现是free
只有free(一个没有malloca)的地址的时候,程序会卡住/崩溃
这个情况发生在new数组的时候,有效地址会 -= 4,也就是头部加了一个记录长度的内存

C++中的new operator、operator new与placement new

https://www.cnblogs.com/luxiaoxun/archive/2012/08/10/2631812.html
https://www.cnblogs.com/likaiming/p/9393083.html
都在这了

可变参数宏

#define  link(a,b) a##b
int main()
  {
  	ll ca = 0;
  	cout << cp(c,a) << endl;

中,##代表字符串连接
但是,在可变参数宏中

#define FOO(...) f(10,##__VA_ARGS__)
int main()
  {
  	cout << FOO() << endl;

这两个##的用处是当可变参数宏为空时,避免f(10,)
也就是消除多余的逗号
具体见这个博客 http://blog.sina.com.cn/s/blog_af95b18b01018o9y.html

链接与全局变量

强符号 : 函数名,或者已经初始化的全局变量
弱符号 : 未初始化的全局变量
多强报错
一强多弱选强
多弱的时候...任选一个,这就非常的阴间,会导致非常阴间的错误

标准库元函数conditional

conditional不是惰性求值...
什么是惰性求值呢,简单来说就是

ll *p = new ll(10);
std::cout << (p == 0 ? 0 : *p) << "\n";

p == 0的时候就不会执行*p
在c++的位运算也是惰性求值的
但是,conditional不是惰性求值的,当你写出类似上述代码的时候
编译器会不断的做实参演绎...有时候conditional的第二个参数是死循环...编译器就会编译到死机...

UB摧毁一切定义

运算中的各种阴间溢出导致的UB
特别是有符号整形的溢出是UB...一些运算在开O2优化的时候会直接导出非常诡异的错误

O2优化下,UB很容易爆出

不开O2你的代码可能在很正常的运行
但是...开O2之后,一切都变了
比如你原本的代码会数组越界,开O2有时会直接死循环...这种错误还比较难查

模板类中静态成员引发的全局变量构造顺序问题

...挺阴间的

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;

template<typename T>
struct wapper
  {
  	static set<T> val;
  	using type = T;
  	T value;
  	wapper()
  	  {
  	  	val.insert(value = mex());
		}
  	operator T ()
  	  {
  	  	return value;
		}
	ll mex()
	  {
	  	for (T i = 0;;i++)
	  	  if (val.count(i) == 0)
	  	    return i;
	  	return -1;
	  }
  };

template<typename T> 
set<T> wapper<T>::val = set<T>();
wapper<ll> a;
int main()
  {
	return 0;
  }

wapper a;的初始化顺序在模板静态变量的前面...操作没初始化的set直接re
解决方案1 :大力偏特化

template<> 
set<ll> wapper<ll>::val = set<ll>();
wapper<ll> a;

解决方案2 :大佬的做法(不太懂...慢慢理解

塞静态函数里面

作为静态函数的静态变量存在

以避开顺序问题

多线程 有可能的话 可以使用 thread_local

搜了一下...全局变量初始化这块有一些阴间东西...特别是不能依赖多个头文件的全局变量的初始化顺序...
再加上特殊的模板静态变量...qs非常阴间

define + 模板

#define CREATE_NAME(type,type_name)  template<> struct typeinfo< type >     \
	  {                             \
	  	static std::string name()   \
	  	  {                         \
	  	  	return type_name;       \
			}                       \
	  }

不知道为啥不能写成

#define CREATE_NAME(type,type_name)    \
template<> struct typeinfo< type >     \

还有一个很阴间的

#define CREATE_NAME(type,type_name)  template<> struct typeinfo< type >     \
	  {                             \
	  	static std::string name()   \
	  	  {                         \
	  	  	return type_name;       \
			}                       \
	  }
	using ll = long long int;
	CREATE_NAME(ll,"ll");
	CREATE_NAME(long long int,"ll");

CREATE_NAME(ll,"ll");这个是无效的...不知道为啥...必须写成CREATE_NAME(long long int,"ll");...测试的时候没测出来...引发了一堆错才查到...
特别是CREATE_NAME(ll,"ll");这可以通过编译...没有任何报错...阴间东西

posted @ 2021-05-26 21:55  XDU18清欢  阅读(179)  评论(0编辑  收藏  举报