一下手写程序就发现各种的不确定和出错,汗.
1、结构体的定义
(1)
struct NAME
{
Type1name1;
Type2name2;
};
(2)
typedef struct
{
Type1name1;
Type2name2;
}NAME, *pNAME;
(3)
struct
{
Type1 name1;
Type2 name2;
} NAME;
这三种结构体的定义中,(1)、(2)是正确的(3)错误
2、强制类型转换的优先级低于 成员访问运算符
(NAME*)arg->file //1、arg->file 2、将其强制转换为(NAME*)
3、vector的push_back(X)方法,存的是X的副本。访vector保证随机问,因此当连续内存不足时会,从新开辟更大的空间,将所有元素赋值到新的空间。将vector中某个元素的地址作为参数传递给被调用的函数,是不安全的。
4、若想向被调函数传递vector中的元素的地址,则事先一次性分配好vector的大小,然后采用下标赋值的方法向vector中增加元素。不要使用push_back()、insert()。
5、参数传递,当采用传递指针或传递引用的方式时,一定要注意参数的作用域问题,保证在被调函数返回前,1、变量地址不变,2、变量值不变
下面通过例子来体会一下
struct T_arg
{
char* file;
int num;
};
int main(int argc, char* argv[])
{
for(int i = 1; i < argc ;i++ )
{
T_arg targ;
targ.file = argc;
targ.num = i;
pthread_t id2;
int ret2 = pthread_create(&id2,NULL,thread_insert,(void*)&targ);
}
return 0;
}
上段代码,想在线程中使用传入的结构体变量targ中的值,但实际上能否获取到targ中的值,就靠运气了,通常会伴随着 Segmentation fault core dumped 。原因在于targ是在for循环中的,局部变量,在一次for循环结束后空间就被释放了,此时在线程中访问的指针就是野指针,core dumped在所难免。若释放前该线程的执行已经结束,那么我们就很幸运的获取到了我们想要的值,而大多数情况下,我们是不走运的。当然,既然我们知道了问题所在,我们就可以让不确定变为确定。于是,有了下段代码:
struct T_arg
{
char* file;
int num;
};
int main(int argc, char* argv[])
{
std::vector<T_arg> vtarg;
for(int i = 1; i < argc ;i++ )
{
T_arg targ;
targ.file = argc;
targ.num = i;
vtarg.push_back(targ);
pthread_t id2;
int ret2 = pthread_create(&id2,NULL,thread_insert,(void*)&vtarg[i-1]);
}
return 0;
}
在这段代码中,我们试图通过一个vector来保存局部变量,来延长它的生存期,push_back(X),向vector中追加X的一个副本,这样即使X消失了,对vector也没有影响,当运行程序发现,在线程中依然要靠运气才能访问到。这是神马情况?好一段百思不解之后突然意识到了,vector的动态开辟内存问题。如前文第3点所总结。通过下段代码验证一下:
struct T_arg
{
char* file;
int num;
};
int main(int argc, char* argv[])
{
std::vector<T_arg> vtarg(10);
for(int i = 1; i < argc && i <= vtarg.size() ;i++ )
{
T_arg targ;
targ.file = argc;
targ.num = i;
vtarg[i-1] = targ;
pthread_t id2;
int ret2 = pthread_create(&id2,NULL,thread_insert,(void*)&vtarg[i-1]);
}
return 0;
}
此时,在线程能正常访问到,我们传入的变量。此段代码仅用来证明上段代码的问题是因为vector的动态分配内存问题。要达到这样的效果,还可可以采用其他更优雅的方式。