homework-08

上次作业中,已经提到了C++ 11的特性。不过,光说不练假把式,这次作业中,我们就对此进行验证。

 

进行测试的4个项目分别为:

1.变量作用域和生命周期

2.堆和栈

3.unique_ptr和shared_ptr

4.分割url

 

为了保证测试的有效性,先要检测编译器对于C++ 11的支持情况。以下是目前主流编译器的支持情况:

http://developer.51cto.com/art/201303/384630.htm

 

由于Clang编译器对于C++ 11的支持比较不错,所以本次我们就选择了Clang作为编译环境

 

从中我们可以看到,编译器是3.3版本,支持本次我们需要用到的所有特性。

 

1.变量作用域和生命周期

这个测试主要是让我们理解变量作用域的概念,所以我们可以使用如下代码:

int main()
{
    int v = 1;
    cout << "In level 1: v=" << v << endl;
    {
        int v = 2;
        cout << "In level 2: v=" << v << endl;
    }
    cout << "Back to level 1: v=" << v << endl;
    return 0;
}

main第一层的v只管第一层,第二层的v只管第二层,第二层的v不会影响到第一层的。如图所示:

 

运行结果如下:

 

与上述解释相符。

 

2.堆和栈

堆和栈是一个容易上新手感到困惑的概念。其实很简单,只要这样理解:栈空间会自动消失,堆空间如果不释放,就不会消失。就类似第一个问题里面,栈的变量都是局部变量,出了那个局部,变量就消失了。比如如下代码:

#include <iostream>
using namespace std;
int *getValueInStack()
{
    int *v;
    *v=9210;
    return v;
}
int *getValueInHeap()
{
    int *v;
    v = new int;
    *v=9210;
    return v;
}
int main()
{
    cout << "In heap: v=" << *getValueInStack() << endl;
    cout << "In stack: v=" << *getValueInHeap() << endl;
    return 0;
}

getValueInStack是从栈里面获得一个变量

getValueInHeap是从堆里面获得一个变量

现在的编译器已经十分智能了,帮我们发现了这个错误,并给出了警告。如果我们不管这个警告,继续执行的话,就会产生非法访存的段错误:

但是,当我把main()函数里两句话换一下位置以后,再加上点修改,就产生了奇妙的现象:程序能输出一个结果,不过非常诡异。

#include <iostream>
using namespace std;
int *getValueInStack()
{
    int *v;
    *v=9210;
    cout << "In getValue(): v=" << *v << endl;
    return v;
}
int *getValueInHeap()
{
    int *v;
    v = new int;
    *v=9210;
    cout << "In getValue(): v=" << *v << endl;
    return v;
}
int main()
{
    cout << "In heap: v=" << *getValueInHeap() << endl;
    cout << "In stack: v=" << *getValueInStack() << endl;
    return 0;
}

这段代码是在我输入错误的时候打进去的,可是却能神奇的输出结果。对于这个奇妙的现象,我在Windows 8.1(编译环境Visual Studio 2013)和Mac(Clang & LLVM 3.3)下都进行了测试。居然是不一样的,windows下这里会报错。

 

由于这个错误,我猜测Windows和Mac有着微妙的差别:Windows编译器对参数是从右往左解析的,Mac是从左往右的。所以Mac在执行getValueInStack之前已经输出了"In stack:"字符串,所以getValueInStack返回的地址的空间先前已经被字符串指针申请过了,所以不会报错。而windows是从右向左的,执行函数之前,那片空间还没有被申请,所以就产生了非法访问。

 

3.unique_ptr和shared_ptr

 

这个真的是一个激动人心的想法,本来C语言的内存泄漏问题就比较严重,有了这个以后就可以在很大程度上避免这个问题。

 

先说unique_ptr,这个的意义就在于一块空间只能有一个指针指向它。下面一张图表示了一个空间指针的交接:

 

unique_ptr是不能直接传值的,比如如下代码在编译时就会直接报错:

#include <iostream>
#include <memory>
using namespace std;
int main()
{
    std::unique_ptr<int>p1(new int(5));
    std::unique_ptr<int>p2=p1;
    return 0;
}

为了实现这个转移功能,我们就需要修改代码:

#include <iostream>
#include <memory>
using namespace std;
int main()
{
    std::shared_ptr<int>p1(new int(5));
    std::shared_ptr<int>p2 = p1;
    cout << *p1 << endl;
    cout << *p2 << endl;
    return 0;
}

move()函数进行了交接操作,p1内存归p2所有,p1变成无效指针,运行起来能输出p1,输出p2就会产生错误

然后就顺利完成了

 

unique_ptr的意义在于,有效防止了指针悬挂,以及由此引起的非法访问操作。

 

shared_ptr

感觉这个就像个超级保姆,有效避免了内存泄漏。

#include <iostream>
#include <memory>
using namespace std;
int main()
{
    std::shared_ptr<int>p1(new int(5));
    std::shared_ptr<int>p2 = p1;
    cout << *p1 << endl;
    cout << *p2 << endl;
    return 0;
}

shared_ptr的意义在于,统一管理了指针的分配,在没有指针指向空间的时候立即释放空间,很大程度上避免了内存泄漏。

 

4.url分割

要求:

1. 类的定义和使用,基本成员是否完整

2. 输入参数的检查及其他鲁棒性的考虑

3. STL和C++11元素的使用

4. 除http://之外, 是否有考虑ftp:// site:// 等情况

5. 是否考虑url中的中文

6. 算法是否简洁高效

7. 代码风格

 

 C语言实现

我的代码做到了

绝对robust,保证不会有溢出,哪怕100W的字符进来也不会

对于所有符号通吃

url中文也毫无压力

算法是O(1)复杂度

代码风格规范

#include <stdio.h>
#define isChar(x) (x>='a'&&x<='z'||x>='A'&&x<='Z'||x>='0'&&x<='9'||x=='-'||x<0)
int main()
{
    char c;
    int inWord = 1;
    while ((c=getchar())!='\n') {
        if (isChar(c)) {
            inWord = 1;
            printf("%c", c);
        } else if (inWord) {
            printf(", ");
            inWord = 0;
        }
    }
    printf("\n");
    return 0;
}

中文的实现主要在于字符的判断

以上的代码十分简单,但是有个小问题,不支持"://"的判断,不过不要紧,稍加改动就可以:

#include <stdio.h>
#define isChar(x) (x>='a'&&x<='z'||x>='A'&&x<='Z'||x>='0'&&x<='9'||x=='-'||x<0)
int main()
{
    char c;
    int inWord = 1, readHead = 0;
    while ((c=getchar())!='\n') {
        if (isChar(c)) {
            inWord = 1;
            printf("%c", c);
        } else if (inWord) {
            printf(", ");
            if (!readHead) {
                if (c != ':') break;
                if (getchar() != '/') break;
                if (getchar() != '/') break;
                readHead = 1;
            } else {
                inWord = 0;
            }
        }
    }
    if (!readHead) {
        printf("\rNot a valid URL!");
    }
    printf("\n");
    return 0;
}

 

 

经过这样的修改,程序就具有了超强的鲁棒性完全不怕数据溢出,哪怕几千万个字节的输入也都可以分割。

程序也有了超强的性能内存占用几乎为0,可以以超高的吞吐量处理流数据

中文的支持,统统能够分割。

简洁的代码

url完整性检查

最后,还有跨平台(Windows和OS X),跨编码集的(GBK与UTF-8)支持:

C++代码(使用STL):

#include <iostream>
#include <string>
#include <vector>
#define isChar(x) (x>='a'&&x<='z'||x>='A'&&x<='Z'||x>='0'&&x<='9'||x=='-'||x<0)
using namespace std;

vector<string> split(string s)
{
    int i = 0, begin, inWord = 0;
    vector<string> ret;
    for (i=0;i<s.size();i++) {
        if (!inWord && isChar(s[i])) {
            begin = i;
            inWord = 1;
        } else if (inWord && !isChar(s[i])) {
            ret.push_back(s.substr(begin, i-begin));
            inWord = 0;
        }
    }
    return ret;
}

int main()
{
    string s;
    int i;
    getline(cin, s);
    s = s+'\n';
    if (s.find("://") == string::npos) {
        cout << "not a url" << endl;
        return 0;
    }
    vector<string> v = split(s);
    if (v.size() > 0) {
        cout << v[0];
    }
    for (i=1;i<v.size();i++) {
        cout << ", " << v[i];
    }
    cout << endl;
    return 0;      
}

使用了两个类,一个是srting,另一个vector。先判断是否有字串”://”,然后就进行分割操作即可。分割的结果存入STL提供的vector中。

 

posted on 2013-11-18 01:18  不想嚣张  阅读(204)  评论(0编辑  收藏  举报

导航