动态库加载
介绍动态库文件(so文件)加载的相关内容,包括动态库dl的基本使用,利用LD_PRELOAD给glibc库函数添加钩子/系统钩子,C++中动态库加载和设计等。
dl库使用:dlopen APIs
dl库主要包括dlopen dlsym dlclose dlerror四个接口。
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);
char *dlerror(void);
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);
//Link with -ldl.
- dlopen(filename, flag)
dlopen会在特定的目录下查找filename,默认如/lib;/usr/lib;LD_LIBRARY_PATH;/etc/ld.so.cache
等,但是不包括当前目录。如果需要当前目录,需要加上./
来标识。dlopen('./module.so', RTLD_LAZY)
。
一些特定的FLAG标识了符号绑定的时间、顺序和可见范围,常用的有RTLD_LAZY RTLD_NOW RTLD_GLOBAL RTLD_NOLOAD(常用于重新修改SO文件的Flag)
- dlsym(handle, symbol)
有两个特殊的伪handle用于dlsym操作,RTLD_DEFAULT和RTLD_NEXT
,通常会被用来做函数钩子。
- error_dlsym = dlerror()
用于获取dl库函数出错的原因。但dlsym接口在某些情况下执行正确也会返回NULL,因此只能通过dlerror()的返回值error_dlsym来判断是否出错。
// reset errors
dlerror();
hello_t hello = (hello_t) dlsym(handle, "hello");
const char *dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol 'hello': " << dlsym_error <<
'\n';
dlclose(handle);
return 1;
}
- dlclose(handle)
所有由dlopen打开的句柄理论上应该由dlclose()释放。
关于const和引用的重载
最近学习C++11新特性右值引用的过程中重新复习了一下引用,重载等概念,总结一下:
const与引用(&)修饰
const与引用是对参数调用过程中的修饰,在函数重载时,有些时候加或者不加修饰符是会引发冲突。
void fun1(int &)
{
}
void fun1(int const)
{
}
以上述代码为例,总结出了一下几种组合是否会出现redefinition冲突
无修饰 | const | & | const + & | |
---|---|---|---|---|
无修饰 | x | o | o | |
const | x | o | o | |
& | o | o | o | |
const + & | o | o | o |
从上表可以看出,对于非引用类型,const不能作为签名的区分,对引用类型没有这个限制。引用可以作为签名的区分。但是在函数调用时,由于调用实参的类型不同,会导致调用方法的二义性(ambiguous)。
C++11 共享内存
关于cout共享:
//描述: t1: 使用cout输出"thread function\n" main:使用cout输出"main thread"
//问题: 两个不同线程(t1 main)对cout的使用会产生冲突
//解决:使用std::mutex解决
#include <mutex>
std::mutex mu;
void shared_cout(std::string s1, int id)
{
mu.lock();
std::cout << s1 << id << std::endl;
mu.unlock();
}
只读的数据不会有数据竞争问题
STL与std::algorithm
STL:: 功能What 底层实现How 算法优势Why
count: 返回searchValue出现的次数,功能类似于find;
vector<int> ivec;
cout<<count(ivec.begin() , ivec.end() , searchValue);
count_if: 返回区间中满足条件的元素
#include <vector>
#include <algorithm>
#include <iostream>
bool greater10(int value)
{
return value >10;
}
int main()
{
using namespace std;
vector<int> v1;
vector<int>::iterator Iter;
v1.push_back(10);
v1.push_back(20);
v1.push_back(10);
v1.push_back(40);
v1.push_back(10);
cout << "v1 : ";
for (Iter = v1.begin(); Iter != v1.end(); Iter++)
cout << *Iter << " ";
cout << endl;
vector<int>::size_type result1 = count_if(v1.begin(), v1.end(), greater10); //count_if算法返回使谓词函数返回条件成立的元素个数
cout << "The number of elements in v1 greater than 10 is: "
<< result1 << "." << endl;
return 0;
}
operator++的重载
一般类型会重载operator++的两种形式,无参数/前缀版本operator++()
和带int参数的后缀版本operator++(int)
。其中,后缀版本在调用时会被编译器自动标注为a.operator++(0)
。
注意:这两个函数的返回值:前缀版本:A&,后缀版本:A,或者会加上常量修饰符const A
通常,在后缀版本的实现中会调用前缀版本函数。
#include <iostream>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <memory>
class UPInt {
public:
UPInt() : value(0) {
}
UPInt& operator++() {
*this += 1;
return *this;
}
const UPInt operator++(int) {
UPInt old = *this;
this->operator++();
return old;
}
UPInt& operator+=(int rValue) {
value += rValue;
return *this;
}
int getValue() {
return value;
}
protected:
int value;
};
using namespace std;
int main()
{
UPInt i;
cout << &i << endl;
cout << &(i++) << endl;
//std::cout << va2.size() << std::endl;
}
vector**:
- v2(v1.begin(), v2.end()-1)
- size
- push_back
- begin/end
- T& front /back (都返回引用)
- void pop_back (删除尾部元素)
- operator []
- erase(v1.begin()) / erase(v1.begin(), v1.begin()+2)
- insert(v1.begin(), 100)
string:
- str1(10, ‘a’)
- length()
bind使用
它提供一个任意的函数对象(仿函数)、函数、函数指针、成员函数指针。 它可以绑定任意的参数。bind 没有对函数对象有任何的要求。返回值是一个函数对象。
#include <iostream>
#include <functional>
#include <memory>
using namespace std;
class A
{
public:
A(int a = 0)
{
this->a = a;
}
void print(int c)
{
std::cout << a << " " << c << std::endl;
}
static void print2(int c)
{
std::cout << c << std::endl;
}
private:
int a;
};
struct Func {
void operator()(int x) {
cout << x << endl;
}
} f;
int main()
{
A a[2] = {1,2};
bind(A::print, a, placeholders::_1)(3);
bind(A::print, a[0], placeholders::_1)(3);
bind(A::print, shared_ptr<A>(new A()), placeholders::_1)(3);
//
bind(A::print, a+1, placeholders::_1)(4);
bind(A::print2, placeholders::_1)(42);
//对于函数对象,可能还需要指明返回值类型
bind<void>(f, 3)();
}
#ouput
1 3
1 3
0 3
2 4
42
3