vector<T> 和 T[] 内存地址区别

2016-05-05 16:19:14 +08:00
 aigebiu

用 libnetfilter_queue 获得数据包, libtins 操作数据包,放回 netfilter 时出现问题:

vector<uint8_t> vec = pkt.serialize();
nfq_set_verdict(qh, id, NF_ACCEPT, size, &vec[0]);

上面这样,(据我测试)只有长度 135 字节以上的数据包才能成功放回,而这样:

uint8_t arr[MAX_BUFSIZ];
copy(vec.begin(), vec.end(), arr);
nfq_set_verdict(qh, id, NF_ACCEPT, size, arr);

就完全没问题。

为什么呢?&vec[0] 和 arr 的地址有什么区别么?

按理说 vector 也是一段连续内存,应该一样的啊。求解,多谢!

3460 次点击
所在节点    C
38 条回复
colatin
2016-05-06 00:09:44 +08:00
@colatin 记错了,是 bool 类型的
colatin
2016-05-06 00:15:45 +08:00
应该是内存池和对齐的问题
proudzhu
2016-05-06 09:03:51 +08:00
人家 vector 就不是给你这么用的,出问题了去看标准库实现,猜来猜去没啥用
zwzmzd
2016-05-06 09:21:38 +08:00
试一下如下的代码呢?

···
vector<uint8_t> v_arr(MAX_BUFSIZ);
copy(vec.begin(), vec.end(), v_arr.begin());
nfq_set_verdict(qh, id, NF_ACCEPT, size, &v_arr[0]);
···

我看了一下你提到的两种实现,第一种使用 vector 的实现,主要数据是放在堆中的;而第二种开辟临时数组的方式,数据是存放在栈上的。相对来讲,数据放在堆上很有可能因为编程者的失误导致部分区域被覆盖,建议检查下之前有没有内存越界的错误。

C++里面我一直是使用 vector+resize()代替 malloc()的,这样有个好处是块临时变量会在块结束时自动释放。用到现在还没发现&vec[0]和 arr[]有任何区别
linux40
2016-05-06 10:34:08 +08:00
@zwzmzd &vec[0]和 arr[]没区别是建立在你用的 Alloc 是 std::allocator ,标准没有说 Alloc::pointer 一定是指针(T*)哟,标准也没有说&t 的返回值一定是指针哟。
zwzmzd
2016-05-06 11:01:50 +08:00
@linux40 是指 operator& 重载么? LZ 遇到的应该不是这个问题吧
aigebiu
2016-05-06 11:22:36 +08:00
@zwzmzd 这样没问题。但就像我 14 楼提到的,直接在 vec.reserve(MAX_BUFSIZ)也可以修复问题,静态开一个 vector 相当于调 reserve ,仍然是在堆上分配内存吧。而且 new char[] 在堆上也没问题,应该不是堆/栈的原因。

顺便纠正之前的几个错误,一个是 64 位 ub 下是 121 字节临界(之前忘减 14 字节 eth 头了),不过反正这个数的绝对值意义不大,也无所谓。
另一个可能的错误是,之前认为是内存分配的原因,但我自己写了个 allocator ,每次都在全局上 new 内存,问题仍然出现,而且临界大小不变。

我写的 allocator patch : https://gist.github.com/isofew/2ffa93faf6ebe3899de55b87115e1551

@colatin
@kkhaike
@boydfd
@linux40

uint8_t arr[MAX_BUFSIZ] 静态开输出如下:
alloc 29 byte(s) at 30174048
&vec[0]: 30174048, arr: 140734511709248
dealloc 29 byte(s) at 30174048

alloc 128 byte(s) at 30174208
&vec[0]: 30174208, arr: 140734511709248
dealloc 128 byte(s) at 30174208

new uint8_t[size] 动态开输出如下:
alloc 29 byte(s) at 21465952
&vec[0]: 21465952, arr: 21466000
dealloc 29 byte(s) at 21465952

alloc 128 byte(s) at 21466160
&vec[0]: 21466160, arr: 21466304
dealloc 128 byte(s) at 21466160

不管哪种开法,都是&vec[0]小包不行大包可以, arr 全都可以。
aigebiu
2016-05-06 11:44:32 +08:00
新发现,如果静态分配 vector 的内存,问题就解决了;如果用 malloc 申请内存,问题也解决了。
看来问题要变成 new 和 malloc 的区别了 233
除了调 constructor 外还有什么区别呢?请教楼上诸位了

输出:
(static) alloc 29 byte(s) at 140733249528912
&vec[0]: 140733249528912, buffer: 140733250577904
dealloc 29 byte(s) at 140733249528912

malloc 29 byte(s) at 35519328
&vec[0]: 35519328, buffer: 140731255293104
free 29 byte(s) at 35519328

就不传 patch 了,静态的大概是这样:
value_type pool[1<<20];
size_type cur = 0;
pointer allocate(size_type num, const void* = 0)
{
pointer p = &pool[cur];
cur += num;
std::cerr << "(static) alloc " << num << " byte(s) at " << (size_type)p << std::endl;
return p;
}

动态( malloc )的大概是这样:
pointer allocate(size_type num, const void* = 0)
{
T* p = (T*)(malloc(num * sizeof(T)));
std::cerr << "malloc " << num << " byte(s) at " << (size_type)p << std::endl;
return p;
}
void deallocate(pointer p, size_type num)
{
std::cerr << "free " << num << " byte(s) at " << (size_type)p << std::endl;
free((void*)p);
}
3dwelcome
2016-05-06 11:49:22 +08:00
很负责的告诉楼主、 vector 内存是连续的、不管那个 stl 实现都是如此。

你的问题最大可能性、是预留空间不足。库里都是指针、没办法帮你修正 vector 数组大小。而你程序外部的修正、很可能把库里记录的地址给冲掉了。
araraloren
2016-05-06 11:56:36 +08:00
@aigebiu `gcc`的`stl`实现中`vector`本身默认的`allocator`就是简单的`new`操作,而对于内置类型`uint_8`并没有什么构造区别
aigebiu
2016-05-06 12:02:19 +08:00
@araraloren 是,内置类型没有构造一说,所以我在考虑“调 constructor 外还有什么区别”。 27 、 28 楼里提到,在自己实现的 allocator 中,用 new 就有问题,用 malloc 就成功了,说明他俩分到的内存是有区别的。
aigebiu
2016-05-06 12:04:47 +08:00
@3dwelcome 能否详细讲下预留空间不足的问题?为什么同样是小空间,用 malloc 给 vector 开的内存就没问题呢?
aigebiu
2016-05-06 12:52:38 +08:00
@aigebiu
@araraloren
@3dwelcome 抱歉 刚才仔细看了下 malloc 也有问题,只有静态分配的没问题。(开了个 pool 数组的那个)
@zwzmzd 这样看来,可能确实和堆/栈有关。
araraloren
2016-05-06 14:08:48 +08:00
@aigebiu 那就是了,因为`new`的实现也是简单的调用`malloc`,并没有什么太高级的东西。。
还有我再次想说的是,不要那么使用`vector`,自己实现一个简单的指针资源管理都比直接用`vector`强。。
aigebiu
2016-05-06 14:34:28 +08:00
@araraloren 嗯是 要不是因为它提供的接口是 vector 我也不愿意这么折腾 自己 malloc free 最方便 谢谢提醒
neoblackcap
2016-05-06 14:41:01 +08:00
@aigebiu 返回 vector 这样的容器很好啊。你 vec 变量生命周期完了那么久自己释放资源了,你 malloc 跟 free 还有可能忘记了。
yuyang1110
2016-05-06 18:23:45 +08:00
@aigebiu 跑个题,其实可以用 vector.data() http://en.cppreference.com/w/cpp/container/vector/data
linux40
2016-05-07 09:46:41 +08:00
new 并不是简单的 malloc ,这样认为的,自己回去补充知识吧。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/276547

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX