具有pop_back函数的类模板向量不能按我的意图工作

时间:2017-05-29 23:28:30

标签: c++ vector

protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
    if (container is ListViewItem cont)
    {
        if (cont.Tag != null && long.TryParse(cont.Tag.ToString(), out var token))
        {
            cont.UnregisterPropertyChangedCallback(ListViewItem.IsSelectedProperty, token);
        }

        cont.Tag = cont.RegisterPropertyChangedCallback(ListViewItem.IsSelectedProperty, (s, e) =>
        {
            cont.ContentTemplateSelector = null;
            cont.ContentTemplateSelector = this;
        });

        if (cont.IsSelected)
        {
            return SelectedItemTemplate;
        }

        return DefaultTemplate;
    }

    return DefaultTemplate;
}

根据我的理解,pop_back()假设弹出向量的最后一个索引,我对编译的期望是给我一个错误;但是,控制台上的输出表示为:

  

3 3

有人会解释为什么这个程序的编译成功吗?

谢谢。

1 个答案:

答案 0 :(得分:4)

vector<>::operator[]()不会检查向量的大小,因此您的代码会产生未定义的行为。

在您的特定情况下,向量在大小(向量中的项目数)缩小,而不是容量(基础数组的大小)当你致电pop_back()时。这意味着第二个VectorName[1]指向未使用但存在的内存。例如,如果我们稍微编辑您的示例以检查容量和大小:

#include <iostream>
#include <vector>

using namespace std;

int main(){

    vector<int> VectorName;

    VectorName.push_back(2); // |[2]|
    VectorName.push_back(3); // |[2, 3]|

    VectorName.pop_back();   // |[2], 3|

    cout << VectorName.size() << endl;
    cout << VectorName.capacity() << endl;

}

输出结果为:

  

1

     

2

您可以在此处查看一个有效的示例:http://coliru.stacked-crooked.com/a/70d5141bdc375b48

正如您所看到的,向量的大小是正确的(1项),但是对VectorName.pop_back()的调用不会降低容量,因此3仍然存在于向量中,但它是不可访问。

通过在调用VectorName.pop_back()后访问第二个项目,您将导致未定义的行为。在您的情况下,您获得3,但使用不同的编译器,体系结构或计算机编译应用程序可能会导致应用程序崩溃(或更糟)!

使用vector<int>::at()代替vector<int>::operator[]()会抛出std::out_of_range异常,导致程序崩溃。这是因为at()函数会检查向量的大小,如果您尝试访问向量中的越界位置,则会抛出异常。也就是说,不要依赖at()函数来检查矢量访问,更喜欢在调用size()之前检查矢量的VectorName[1]

例如,通过再次对代码进行次要编辑,我们可以看到使用at()函数时会发生什么:

#include <iostream>
#include <vector>

using namespace std;

int main(){

    vector<int> VectorName;

    VectorName.push_back(2);
    VectorName.push_back(3);

    cout << VectorName.at(1) << endl;
    VectorName.pop_back();

    cout << VectorName.at(1) << endl;

    return 0;
}
  

3

     

在抛出'std :: out_of_range'

的实例后终止调用      

what():vector :: _ M_range_check:__n(即1)&gt; = this-&gt; size()(即1)

     

bash:第7行:4793中止(核心转储)./a.out

直播示例:http://coliru.stacked-crooked.com/a/8226be85196f54fe

“编译错误”还有一件事。在访问向量之前,编译器不会尝试检查向量的大小,因此编译器将很乐意编译代码而不会出现错误或警告。作为开发人员,您可以对代码执行边界检查。