使用STL string慎用memcpy和void*
项目中常用STL的string,最近遇到些问题,罪魁祸首是memcpy和void*。
1、类中有string成员变量,如果不小心用memcpy拷贝了该类的对象,则string成员变量将被析构两次。这其实就是浅拷贝的错误,实在要用string,又要拷贝,只有自己实现拷贝函数。
struct stInfo
{
int age;
std::string name;
};
int main()
{
stInfo info;
info.name = "dandan";
stInfo* p = new stInfo();
memcpy(p, &info, sizeof(info));
//...
delete p; //p指向的对象被正常删除,成员变量str被删除,string的析构函数被调用,其内存地址被释放
return 0;
}
//程序退出时,对象m被析构,string的析构函数被调用,同一块内存地址再次被释放,抛异常
Crash文件
*** Error in `./a.out': munmap_chunk(): invalid pointer: 0x00007fff70c42c58 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7ada4)[0x7f1aaf626da4]
./a.out[0x400ba8]
./a.out[0x400ad5]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f1aaf5cdb35]
./a.out[0x400999]
======= Memory map: ========
00400000-00401000 r-xp 00000000 fd:01 1070198 /home/Test/a.out
00601000-00602000 r--p 00001000 fd:01 1070198 /home/Test/a.out
00602000-00603000 rw-p 00002000 fd:01 1070198 /home/Test/a.out
0198b000-019bd000 rw-p 00000000 00:00 0 [heap]
7f1aaf5ac000-7f1aaf763000 r-xp 00000000 fd:01 657569 /usr/lib64/libc-2.17.so
7f1aaf763000-7f1aaf962000 ---p 001b7000 fd:01 657569 /usr/lib64/libc-2.17.so
7f1aaf962000-7f1aaf966000 r--p 001b6000 fd:01 657569 /usr/lib64/libc-2.17.so
7f1aaf966000-7f1aaf968000 rw-p 001ba000 fd:01 657569 /usr/lib64/libc-2.17.so
7f1aaf968000-7f1aaf96d000 rw-p 00000000 00:00 0
7f1aaf96d000-7f1aaf983000 r-xp 00000000 fd:01 1704603 /apps/sylar/lib64/libgcc_s.so.1
7f1aaf983000-7f1aafb83000 ---p 00016000 fd:01 1704603 /apps/sylar/lib64/libgcc_s.so.1
7f1aafb83000-7f1aafb84000 r--p 00016000 fd:01 1704603 /apps/sylar/lib64/libgcc_s.so.1
7f1aafb84000-7f1aafb85000 rw-p 00017000 fd:01 1704603 /apps/sylar/lib64/libgcc_s.so.1
7f1aafb85000-7f1aafc85000 r-xp 00000000 fd:01 657577 /usr/lib64/libm-2.17.so
7f1aafc85000-7f1aafe85000 ---p 00100000 fd:01 657577 /usr/lib64/libm-2.17.so
7f1aafe85000-7f1aafe86000 r--p 00100000 fd:01 657577 /usr/lib64/libm-2.17.so
7f1aafe86000-7f1aafe87000 rw-p 00101000 fd:01 657577 /usr/lib64/libm-2.17.so
7f1aafe87000-7f1ab0050000 r-xp 00000000 fd:01 1705451 /apps/sylar/lib64/libstdc++.so.6.0.26
7f1ab0050000-7f1ab024f000 ---p 001c9000 fd:01 1705451 /apps/sylar/lib64/libstdc++.so.6.0.26
7f1ab024f000-7f1ab025a000 r--p 001c8000 fd:01 1705451 /apps/sylar/lib64/libstdc++.so.6.0.26
7f1ab025a000-7f1ab025d000 rw-p 001d3000 fd:01 1705451 /apps/sylar/lib64/libstdc++.so.6.0.26
7f1ab025d000-7f1ab0260000 rw-p 00000000 00:00 0
7f1ab0260000-7f1ab0280000 r-xp 00000000 fd:01 656965 /usr/lib64/ld-2.17.so
7f1ab0474000-7f1ab0479000 rw-p 00000000 00:00 0
7f1ab047e000-7f1ab0480000 rw-p 00000000 00:00 0
7f1ab0480000-7f1ab0481000 r--p 00020000 fd:01 656965 /usr/lib64/ld-2.17.so
7f1ab0481000-7f1ab0482000 rw-p 00021000 fd:01 656965 /usr/lib64/ld-2.17.so
7f1ab0482000-7f1ab0483000 rw-p 00000000 00:00 0
7fff70c24000-7fff70c45000 rw-p 00000000 00:00 0 [stack]
7fff70d18000-7fff70d1a000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
[1] 28037 abort ./a.out
2、void指向有string成员变量的类对象,删除void不能正确析构string成员变量,类的析构函数都不会被调用。谨慎使用void*指向复杂对象,无奈这么用了,删除时记得转回原对象类型指针再删除. 因为delete void * is undefined [-Wdelete-incomplete], 非完全类型。
struct stInfo
{
int age;
std::string name;
};
int main()
{
stInfo info;
info.name = "dandan";
stInfo* p = new stInfo();
memcpy(p, &info, sizeof(info));
void *ptr = p;
//...
delete ptr;
return 0;
}
运行现象:
➜ Test g++ test.cc
alignas.cc: In function ‘int main()’:
alignas.cc:22:9: warning: deleting ‘void*’ is undefined [-Wdelete-incomplete]
22 | delete ptr;
| ^~~
➜ Test ./a.out
➜ Test