Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1073464
  • 博文数量: 77
  • 博客积分: 11498
  • 博客等级: 上将
  • 技术积分: 1840
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-04 11:10
文章分类

全部博文(77)

文章存档

2011年(1)

2010年(16)

2009年(5)

2008年(55)

分类: C/C++

2008-08-31 17:06:31


    Swap Bug in VC8 vs Swap Fix in VC9
    作者:tyc611.cublog.cn,2008-08-31
    VC8引入了Debug Iterator和Checked Iterator,但却存在一个严重的Bug。在描述此Bug之前,我们先来看看描述Debug Iterator和Checked Iterator的内部工作原理。

    为了使Iterator具有检错功能,Debug Iterator和Checked Iterator内部都添加了额外的数据,例如指向父容器的指针。而对于Debug Iterator,容器中还提供了一个单向链表,用来记录该容器的所有Iterator。通过这些额外的指针,迭代器就可以做一些检查功能,比如参与运算的两个迭代器是否来自同一容器、迭代器是否已经失效,等等。

    现在,让我们来看看VC8存在的Bug,也是就是所谓Swap Bug。当禁用_HAS_ITERATOR_DEBUGGING(Debug Iterator)和启用_SECURE_SCL(Checked Iterator)时,如果我们交换(Swap)两个容器对象,此时就会出现Swap Bug。在使用Checked Iterator时,容器并没有相应的方法能够找到它的迭代器(只有迭代器通过内部的指针找到容器)。因此,在两容器对象交换后,它们的所有迭代器都指向了错误的容器对象,因此进一步使用这些迭代器时就会出现错误。而C++标准(23.1/10)要求容器对象交换后,迭代器仍然有效。这样,就产生了Swap Bug。由于Debug Iterator的容器有一个所有迭代器的单向链表,在交换时能够更新相应迭代器的父容器指针,因此不会出现Swap Bug。

    为了解决这个Bug,VC9为每个容器(std::string除外)添加了一个额外的动态分配的对象,被称为"aux object“(辅助对象)。容器拥有一个指针指向它的“aux object”,而该“aux object”拥有一个指针回指容器。此时,Checked Iteratro以前的父容器指针改为指向父容器的“aux object”。在交换容器对象时,同时交换它们的“aux object”对象即可,这样就解决了之前的Swap Bug。
 
    但新的解决方案有两个缺点:其一,由于引入了一个间接层,效率有所下降;其二,容器占用了额外的空间。

    前面提到,VC9为其它容器都进行Bug Fix,唯独没有修改std::string(及相应的std::wstring)。原因在于,std::string(及std::wstring)被直接编译在msvcp90[d].dll中,并在编译时设置_SECURE_SCL=1(Debug版还设置了_HAS_ITERATOR_DEBUGGIN=1)。因此,在使用string(及wstring或者basic_string)时,如果使用它的迭代器就需要注意避开Swap Bug。事实上,大多数时候,我们都是使用它的下标索引形式来访问字符串数据。作为用户的我们也只能希望在VC10中能够解决这个问题。

    另外,由于_SECURE_SCL和_HAS_ITERATOR_DEBUGGIN设置不同,产生的代码中容器对象和迭代器对象也会有所不同。因此,在使用 Debug Iterator和Checked Iterator时,我们务必保证所有编译单元都使用了相同的_SECURE_SCL和_HAS_ITERATOR_DEBUGGIN设置。目前编译器还无法检测到这个不一致问题,不知道在VC10中是否能够提供相应的检测功能。

    由于在标准算法实现中,迭代器检查被提到循环外面,因此建议尽量使用C++标准算法,而不要手写循环。这样,可以有效地减少迭代器内部的检查次数,从而提高程序运行效率。

    最后,附上一小段程序,让我们来看看在启用和禁用_SECURE_SCL的情形下,容器大小的变化。

程序源码:
#include
#include
using namespace std;

int main()
{
    vector v;
    cout << sizeof(v) << endl;

    return 0;
}

启用_SECURE_SCL(默认):
F:\tmp>cl /EHsc /nologo test.cpp
test.cpp

F:\tmp>test.exe
24

禁用_SECURE_SCL:
F:\tmp>cl /EHsc /D "_SECURE_SCL=0" /nologo test.cpp
test.cpp

F:\tmp>test.exe
16

参考资料:
1. http://blogs.msdn.com/vcblog/archive/2007/08/10/the-future-of-the-c-language.aspx
阅读(1767) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2008-09-21 00:05:08

谢谢,正好在看