C++ std::vector可以使用小缓冲区优化吗?

C++ std::vector可以使用小缓冲区优化吗?,c++,c++11,stdvector,C++,C++11,Stdvector,今天我和同事一起想知道std::vector是否可以实现以利用小缓冲区优化。通过查看C++11草案,我阅读了23.3.1p8 对于标准容器类型(数组除外)的容器a和b,表达式a.swap(b)应在不调用单个容器元素上的任何移动、复制或交换操作的情况下交换a和b的值 起初,这似乎是非法的小缓冲区优化,但根据“仿佛”规则,我们仍然可以对非类类型进行小缓冲区优化(因为我们无法观察到正在进行的复制)。下一个文本似乎更难“愚弄” 交换前引用一个容器中某个元素的每个迭代器应在交换后引用另一个容器中的同一元素

今天我和同事一起想知道std::vector是否可以实现以利用小缓冲区优化。通过查看C++11草案,我阅读了23.3.1p8

对于标准容器类型(数组除外)的容器a和b,表达式a.swap(b)应在不调用单个容器元素上的任何移动、复制或交换操作的情况下交换a和b的值

起初,这似乎是非法的小缓冲区优化,但根据“仿佛”规则,我们仍然可以对非类类型进行小缓冲区优化(因为我们无法观察到正在进行的复制)。下一个文本似乎更难“愚弄”

交换前引用一个容器中某个元素的每个迭代器应在交换后引用另一个容器中的同一元素

这足以阻止对std::vector实现小缓冲区优化吗?是否存在任何其他障碍,或者最终是否可能有SBO的std::vector?

23.2.1/p10/b6:

除非另有说明

  • 函数的作用是:不使引用被交换容器元素的任何引用、指针或迭代器失效。
它没有为
向量
指定“其他”。因此,这将禁止
向量的SBO

string
不受此规则的约束,因为它在21.4.1/p6中没有“另行指定”:

引用的元素的引用、指针和迭代器 基本_字符串序列可能因以下使用而无效: 基本字符串对象:

  • 作为任何标准库函数的参数,并将对非常量基本字符串的引用作为参数。^234
234)例如,作为非成员函数swap()的参数 (21.4.8.8)、运算符>>()(21.4.8.9)和getline()(21.4.8.9)或 basic_string::swap()的参数


除了迭代器失效的问题外,还有一个安全参数可以避免小缓冲区优化

如果写入溢出了
std::vector
,则会导致堆损坏,这很难预测哪些内容会被覆盖,也很难利用它执行任意代码


如果将缓冲区嵌入到局部变量中,则溢出会破坏堆栈,攻击者可能会控制返回地址,这更有用(例如,返回到libc攻击)。

字符串是否具有相同的
交换
子句?llvm项目页面提到使用SBO,这表明:(1)litb引用的规则不适用于字符串,或者(2)尽管有这些规则,但有某种方法可以将SBO与字符串一起使用,或者(3)当libc++作者阅读标准的这一部分时,他们会感到失望。llvm libc++项目页指的是字符串,而不是向量。我相信Johannes指出的swap/iterator注释确实禁止vector的SBO。21.4.1/p6特别允许string::swap使迭代器无效。相关:脱离主题,但我最近在看这篇文章,试图为
移动
找到类似的保证。这似乎很明显,但是将有效迭代器传输到目标容器是否需要
move
?不,我不相信是这样(但我的内存很容易出错)。如果您将迭代器或引用添加到临时对象中,则可能有点太棘手了。:-)然而,我很想看到激励代码的另一个建议。但是
move
不仅仅适用于临时性的,它还适用于您不想复制的持久性结构。激励代码只是在局部变量中构建一个结构,然后将其移动到一个更永久的容器中。(当然,它并不总是移动的,或者我只是从那里开始构建它。)令人质疑的相关:虽然攻击者可能更容易利用堆栈上的溢出,但从开发人员的角度来看,这两种情况都应该被视为完全不受欢迎。堆损坏并不是真的“更好”,只是不可接受。@Leushenko:ASLR并没有修复任何错误,但它仍然被认为是非常理想的深度安全防御。同上,非可执行堆栈。