c,c++随便记记

1. malloc vs calloc

参数不一样这是谁都可以看出来的,呵呵。重要的是calloc会将申请的内存初始化为0,malloc不会


2.setjump & longjump

可以通过setjump,然后调用longjump将栈帧退回到setjump。这对函数能够实现goto不能完成的跨函数跳跃。不过在使用在对函数的时候,要注意寄存器值的变化是否会变化到setjump时的状态,对于静态变量和变量是不一样的 

 

3. vfork vs fork

fork大家用的会多点,对于这个函数,应该用的比较少哦。但是对于fork后会立刻执行exec的情景,这个函数是很适用的。它跟fork之间的区别是:vfork保证子进程先运行,在它调用exec或者exit之后,父进程才可能被调度运行。而且重要的是子进程不会复制父进程的数据,在调用exec之前,是直接用父进程的数据进行运行(可以修改父进程的变量哦)


4. execve 系列

总共6个函数,用于执行一个新的进程程序,这6个函数参数的区别在于是用数组还是。。。,以及是否带环境变量。还有个要注意,只有execve是系统调用,其他都是库函数,最终还是调execve


5. c++的访问修饰符

c++的访问修饰符,只是控制是否可以访问。 不适用于重写,父类private的方法,子类也是可以重写的


6. 命名空间的问题

子类A继承ns::B, 访问B不需要引用ns::,好神奇


7. 类中有指针,而且是类自己申请的

你可能要在析构函数里面释放,而且你需要重写赋值运算操作和拷贝构造函数,无论你是设成不可拷贝,还是深拷贝指针


8. 方法重写overrid

重写基类的方法,可以改变返回值,但是返回值必须是基类返回值的子类


9. 类的静态常量成员初始化

可以在类里面初始化,也可以在cpp文件里面初始化,但是有时候在类里面初始化会报找不到定义,所以还是在cpp文件里面初始化吧


10. 宏 vs 命名空间

宏是不受命名空间保护的,宏放在命名空间里面还是外面都是一样的,全局的


11. 根据左值返回相应的类型

通过一个内部类,重载各种类型转换操作,可以实现根据左值返回对应的类型,有个应用场景,是将字符串转换为需要的类型,比如从xml文件里面读取需要的类型


12. const 引用会导致复制

const 引用在初始化时如果类型不一致会导致复制一份,而且编译不会报错,比如:

const uint64_t& a = b; (int b = 3)

其实a跟b指向的不是同一个内存对象,那么b变了,a的值还是不变的


13. inline可以避免重复定义

如果在头文件里面写函数的实现定义,那么在链接的时候就很容易出重复定义的错误,将函数申明为inline就没问题了


14. 静态成员初始化

全局静态成员和类的静态成员是在main之前初始化,但是你不能控制他们的初始化顺序。函数的局部静态成员在调用时才会进行初始化,如果要保证局部静态成员在main之前初始化,需要一点点技巧,参见boost的singleton实现:

template<typename T>
class Singleton
{
private:
struct obj_creator
{
	obj_creator()
	{
		Singleton<T>::Instance();
	}
	inline void do_nothing() const {}
};
static obj_creator create_obj_; // 通过类静态成员来触发函数调用,来初始化局部静态成员
public:
static T* Instance()
{
	static T obj_;
	create_obj_.do_nothing(); // 据说这个调用是为了防止编译器优化,待研究,有高手的话,请指教
	return &obj_;
}
};


15. 表达式计算的顺序未定义

表达式中各个节点的计算顺序是未定义的,比如

int result = a[0] + 2 * a[++i] + 3 * a[++i];

上面的表达式中的3个节点,计算顺序其实是不定的,导致++i的操作在什么时候计算是未定义,导致程序计算结果的不确定,因此不要写上述情况的代码。


16. 编译时发现说类没申明,但是实际又声明了,找不到原因的话,看看是不是头文件的define冲突了,就是2个头文件的define是一样的,导致另外一个头文件没有加载


17. 类的析构函数默认是非virtual的,如果子类的析构函数是virtual,基类不是,当delete一个指向子类的基类指针时,会core dump







你可能感兴趣的:(c,c++随便记记)