如何在C++语言中删除一个向量?

131 阅读3分钟

是的!是的,但它并不是没有约束。有两种删除矢量的方法。同样,它们也不是没有约束的。一种删除向量的方法是使用向量的析构器。在这种情况下,所有的元素都被删除,但是向量的名字没有被删除。删除一个向量的第二种方法是让它超出范围。通常情况下,任何在作用域中声明的非静态对象在超出作用域时都会死亡。这意味着该对象在嵌套作用域(block)中不能被访问。一个嵌套的作用域是一个外层作用域(块)。一个嵌套的作用域是一个内作用域,它仍然是感兴趣的作用域的一部分。本文将讨论这两种删除向量的方式。

为了在C++中使用向量,程序应该以下列方式开始

#include <vector>

#include <iostream>

using namespace std;

文章内容

销毁向量

任何对象的创建都是在某个作用域中。在本节文章中,向量是在main()函数作用域中创建和销毁的。销毁一个向量的语法是。

a.~X()

其中'a'是向量的名称,而X是向量的类名。矢量是一个从类中实例化出来的数据结构。矢量类的名称是 "vector",所有字符都是小写。如果向量的名字是vtr,那么向量将被销毁,用

vtr.~vector.

下面的程序删除了向量。

 #include <vector>
#include <iostream>
using namespace std;

int main()
{
    vector<char> vtr = {'A', 'B', 'C', 'D', 'E'};

    vtr.~vector();

    for (int i=0; i < vtr.size(); i++) {
        cout << vtr[i] << ' ';
    }
    cout << endl;

    return 0;
}

输出结果是什么都没有,表明所有的向量元素,除了向量的名称,都被擦除了。这很好。上面的输出是通过引用所谓的元素来显示的。如果用迭代器来显示输出呢?考虑一下下面的程序。

#include <vector>

#include <iostream>

using namespace std;

 

int main()

{

    vector<char> vtr = {'A', 'B', 'C', 'D', 'E'};

    vector<char>::iterator it = vtr.begin();

 

    vtr.~vector();

 

    for (it = it; it != vtr.end(); it++) {

        cout << *it << ' ';

    }

    cout << endl;

 

    return 0;

}

输出仍然是空的。在这个阶段,我们可以真正得出结论,当一个向量被销毁时,它的所有元素都被销毁了,除了它的名字。

未销毁的向量名称

由于向量的名字没有随着析构器被销毁,这个名字仍然可以在同一范围内被重新使用。下面的程序说明了这一点。

#include <vector>

#include <iostream>

 

using namespace std;

int main()

{

    vector<char> vtr = {'A', 'B', 'C', 'D', 'E'};

    vtr.~vector();

    vtr = {'F', 'G', 'H', 'I', 'J'};

    for (int i = 0; i < vtr.size(); i++) {

        cout << vtr[i] << ' ';

    }

    cout << endl;

    return 0;

}

输出是

F G H I J

该向量的原始内容有5个字符。这5个元素都被擦掉了。由于向量的名称被重新使用,新的5个字符被作为向量的内容给予。输出结果显示新的内容是正确的。

然而,仍有一个细微的差别。如果新的内容是用push_back()成员函数给出的,输出可能是不完整的,向量中可能有新的字符。下面的程序说明了这一点。

#include <vector>

#include <iostream>

using namespace std;

 

int main()

{

    vector<char> vtr = {'A', 'B', 'C', 'D', 'E'};

    vtr.~vector();

    vtr = {'V', 'W', 'X', 'Y', 'Z'};

    vtr.~vector();

    vtr.push_back('F');

    vtr.push_back('G');

    vtr.push_back('H');

    vtr.push_back('I');

    vtr.push_back('J');

    for (int i = 0; i < vtr.size(); i++) {

        cout << vtr[i] << ' ';

    }

    cout << endl;

    return 0;

}

输出是

p ^ t e U G H I J

输出中缺少'F',还有一些奇怪的字符。最初,向量的内容是用赋值运算符给出的。向量被销毁,然后用赋值运算符再次分配新的内容。向量再次被销毁,这次内容是用push_back()成员函数给出的。输出中缺少'F',而且有一些奇怪的字符。这需要解释。

当一个向量被销毁时,它的所有元素被正式删除。发生的情况是,这些元素被简单地认为不属于该向量,并立即生效,它们的内存位置被指定为可被任何其他代码重新使用,并立即生效。如果这个方案在内部没有得到完美的执行,就像上面的最后一个程序一样,那么就会有麻烦,可能会产生上面的那种输出。

常量向量

当一个向量声明前面有const,表示常量时,它仍然可以被销毁,如上所述。下面的程序说明了这一点。

#include <vector>

#include <iostream>

using namespace std;

int main()

{

    const vector<char> vtr = {'A', 'B', 'C', 'D', 'E'};

 

    vtr.~vector();

 

    for (int i = 0; i < vtr.size(); i++) {

        cout << vtr[i] << ' ';

    }

    cout << endl;

 

    return 0;

}

输出的结果是什么都没有。然而,在这个条件下(const vector),没有元素可以使用erase()成员函数被擦除。

在嵌套的范围内使用名称

用~vector销毁一个向量,会销毁其内容(元素),但不会销毁向量的名称。该名称仍然可以在内部作用域中使用,它仍然是感兴趣的作用域的一部分。下面的程序说明了这一点。

#include <vector>

#include <iostream>

using namespace std;

int main()

{

    vector<char> vtr = {'A', 'B', 'C', 'D', 'E'};

 

    vtr.~vector();

 

    if (1 == 1) {

        vtr = {'K', 'L', 'M', 'N', 'O'};

        for (int i = 0; i < vtr.size(); i++)

            cout << vtr[i] << ' ';

        cout << endl;

    }

 

    return 0;

}

输出是

K L M N O

注意:如果一个向量的名字要被重复使用,它不应该被重新声明。

让出范围

当任何声明的对象超出它的作用域时,它就不能再在它的作用域之外被访问。这意味着它不能再在嵌套的作用域中被访问。然而,它可以在一个嵌套的作用域中被访问。嵌套的作用域仍然是有关的作用域的一部分。

在范围内和范围外的访问

下面的程序说明了如何在作用域中访问一个向量。

#include <vector>

#include <iostream>

using namespace std;

int main()

{

    if (1 == 1) {

        vector<char> vtr = {'A', 'B', 'C', 'D', 'E'};

            for (int i = 0; i < vtr.size(); i++)

                cout << vtr[i] << ' ';

            cout << endl;

    }

 

    return 0;

}

输出是

A B C D E

main()函数作用域嵌套了if-block作用域。在if-block作用域中声明的vtr只能在if-block作用域中被访问。它不能在 if-block 作用域之外被访问。它不能在嵌套 if 块的 main() 函数块之外被访问。下面的程序将无法编译,因为有人试图在其范围之外访问向量。

#include <vector>

#include <iostream>

using namespace std;

int main()

{

    if (1 == 1) {

        vector<char> vtr = {'A', 'B', 'C', 'D', 'E'};

            for (int i = 0; i < vtr.size(); i++)

                cout << vtr[i] << ' ';

            cout << endl;

    }

 

    cout << vtr[1] << endl;

 

    return 0;

}

如果读者试图编译这个程序,就会发出一个错误信息。

嵌套的作用域

一个嵌套的作用域仍然是有关作用域的一部分。下面的程序说明了如何在一个嵌套的作用域中访问一个向量。

#include <vector>

#include <iostream>

using namespace std;

int main()

{

    if (1 == 1) {

        vector<char> vtr = {'A', 'B', 'C', 'D', 'E'};

            if (1 == 1) {

                for (int i = 0; i < vtr.size(); i++)

                    cout << vtr[i] << ' ';

                cout << endl;

            }

        }

 

        return 0;

}

输出是

A B C D E

main()函数块嵌套了第一个if块,该块又嵌套了第二个if块。向量是在第一个if块中声明的。它在嵌套的(内部)if-block中被访问。

与使用析构器相比,让向量在超出范围时死亡的方法看起来更可取。当向量超出范围时,它的名字也会消失。然而,程序员并不总是希望向量在超出范围时死亡。所以,析构函数将不得不偶尔使用。这两种方式都有其局限性。

结论

删除向量的一种方法是使用向量的析构函数。在这种情况下,所有的元素都被删除了,但是向量的名字没有被删除。删除一个向量的第二种方法是让它离开范围。通常情况下,任何在作用域中声明的非静态对象在超出作用域时都会死亡。这意味着该对象在嵌套作用域(block)中不能被访问。嵌套作用域是一个外层作用域(block)。 然而,它可以在一个嵌套的作用域中被访问。一个嵌套的作用域是一个内部作用域,它仍然是感兴趣的作用域的一部分。这两种方式都有约束。在一个内部作用域中的向量不需要在让它离开作用域死亡之前用 ~vector 来销毁。