回首页 回首页 ◎ 设为首页  
◎ 收藏本站  
◎ 给我留言  
  
  首 页  C/C++教程  C++之父的FAQ  C/C++动向  C/C++源代码  C/C++误区  Unix/Linux  下载中心  乱七八糟  蚂蚁的Blog  
  当前位置:首 页 >> C++之父的FAQ >> C++ 风格与技术 FAQ >> [翻译] 数组有何不好之处?
最 近 更 新
[转] 我该把const写在类..
[翻译] 我应该使用按值..
[翻译] 你如何命名变量..
[转] 何种代码布局风格..
[转] “int* p;”和“in..
[翻译] “cout”怎么念?
[转] 宏有什么不好吗?推荐
[翻译] static_cast 有..推荐
[翻译]为何C++里有些东..推荐
[翻译] i++ + i++ 的值..推荐
最 新 推 荐
[转] 宏有什么不好吗?推荐
[翻译] static_cast 有..推荐
[翻译]为何C++里有些东..推荐
[翻译] i++ + i++ 的值..推荐
[翻译] 数组有何不好之..推荐
[转] 为何delete操作不..推荐
[转] 有placement delet..推荐
[翻译] “new”和“mall..推荐
[转] C和C++风格的内存..推荐
[翻译] 为何标准容器效..推荐
热 门 排 行
[转] 我可以写“void ma..
[翻译] 什么是纯虚函数?
[转] 我该把const写在类..
[转] 这个简单的程序…..推荐
[翻译] i++ + i++ 的值..推荐
[转] 我如何从标准输入..
[转] 我怎样才能把整数..
[翻译] static_cast 有..推荐
[转] 宏有什么不好吗?推荐
[转] 我应该怎样处理内..推荐
站 内 搜 索

Web stdcpp.cn
关键词

搜索方式

搜索范围

精确匹配
广 告

[翻译] 数组有何不好之处?


来源:蚂蚁的 C/C++ 标准编程 作者:Bjarne Stroustrup 翻译:antigloss 等级:精品
发布于2007-08-12 10:45 被读715次 【字体:

    从时间和空间的角度来讲,数组是访问内存中连续对象的最佳结构。然而,它同时也是非常底层的数据结构,不当地使用它常常会导致大量潜在的错误。而且,基本上在所有需要用到数组的地方,我们都有更好的替代品。我所说的“更好”是指更易于读写、不易导致错误,以及同等效率。

    和数组如影随形的两个基本问题是:

    • 数组不知道其自身的长度
    • 稍有风吹草动,数组的名字就会转换成指向其首元素的指针
    思考以下一些例子:

                void f(int a[], int s)
                {
                        // 处理 a;a 的长度是 s
                        for (int i = 0; i < s; ++i) a[i] = i;
                }

                int arr1[20];
                int arr2[10];

                void g()
                {
                        f(arr1,20);
                        f(arr2,20);
                }

    第二个函数调用会玷污不属于 arr2 的内存。通常,程序员都不会传递错误的长度给函数 f,但传递参数是个额外的负担,而且不时都会有些人犯错(传递了错误的长度)。我更喜欢使用标准库里的 vector,这样写出来的程序更加简单明了:

                void f(vector< int >& v)
                {
                        // 处理 v
                        for (int i = 0; i < v.size(); ++i) v[i] = i;
                }

                vector< int > v1(20);
                vector< int > v2(10);

                void g()
                {
                        f(v1);
                        f(v2);
                }

    因为数组不知道其自身的长度,所以不能直接进行数组赋值:

                void f(int a[], int b[], int size)
                {
                        a = b; // 并非数组赋值
                        memcpy(a,b,size); // a = b
                        // ...
                }

    同样,我更喜欢使用 vector:

                void g(vector< int >& a, vector< int >& b, int size)
                {
                        a = b;
                        // ...
                }

    vector 的另一个好处是,memcpy() 不能正确处理带有复制构造函数的元素,例如 string:

                void f(string a[], string b[], int size)
                {
                        a = b; // 并非数组赋值
                        memcpy(a,b,size); // 灾难
                        // ...
                }

                void g(vector< string >& a, vector< string >& b, int size)
                {
                        a = b;
                        // ...
                }

    数组的大小在编译时就已固定:

                const int S = 10;

                void f(int s)
                {
                        int a1[s]; // 错误
                        int a2[S]; // ok

                        // 若想增加 a2 的长度,必须改用 malloc() 从堆中分配数组空间,
                        // 然后使用 realloc() 改变分配到的空间的大小
                        // ...
                }

        作为对比:

                const int S = 10;

                void g(int s)
                {
                        vector< int > v1(s); // ok
                        vector< int > v2(S); // ok
                        v2.resize(v2.size()*2);
                        // ...
                }

    C99 允许可变长的局部数组,但 VLA(变长数组,variable-length array)也有其独特的问题。

    在 C 和 C++ 中,数组名“退化”为指针的方式是基本常识。然而,数组退化和继承“互动”时,是非常不妙的。例如:

                class Base { void fct(); /* ... */ };
                class Derived { /* ... */ };

                void f(Base* p, int sz)
                {
                        for (int i=0; i < sz; ++i) p[i].fct();
                }

                Base ab[20];
                Derived ad[20];

                void g()
                {
                        f(ab,20);
                        f(ad,20); // 灾难!
                }

    在后一个函数调用里,Derived[] 被认为是 Base[],以至于当 sizeof(Derived)!=sizeof(Base) 时,余下的代码不再能正常工作。如果我们使用 vector 的话,在编译时就能捕捉到这个错误:

                void f(vector< Base >& v)
                {
                        for (int i=0; i < v.size(); ++i) v[i].fct();
                }

                vector< Base > ab(20);
                vector< Derived > ad(20);

                void g()
                {
                        f(ab);
                        f(ad); // 错误:不能将 vector< Derived > 转换成 vector< Base >
                }

    我发现大量 C 和 C++ 初学者的程序错误都和(错误地)使用数组有关。

原文地址http://www.research.att.com/~bs/bs_faq2.html#arrays

本文版权归 蚂蚁的 C/C++ 标准编程 以及 作者 Bjarne Stroustrup 翻译:antigloss 共同所有,转载请注明原作者和出处。谢谢。



相关专题:C++ 之父的言论
[转] 我该把const写在类型前面还是后面?
[翻译] 我应该使用按值传递还是按引用传递?

上一篇:[转] 为何delete操作不把指针置零?
下一篇:[翻译] 如何使用异常?

共有评论 0 条 网友评分 0分 查看全部评论

查看全部评论

【发表评论】 评分:1分 2分 3分 4分 5分


验证码:

Powered By Www.Xydw.COM Ver1.14 管理
Copyright © 2005-2006 蚂蚁的 C/C++ 标准编程 All Right Reserved. XCMS
粤ICP备06014124号   站长:Antigloss