【问题标题】:How to change a particular element of a C++ STL vector如何更改 C++ STL 向量的特定元素
【发布时间】:2011-02-07 03:06:31
【问题描述】:
vector<int> l;
for(int i=1;i<=10;i++){
   l.push_back(i);
}

现在,例如,如何将向量的5th element 更改为-1

我试过l.assign(4, -1); 它的行为不符合预期。其他向量方法似乎都不适合。

我使用了向量,因为我需要在我的代码中使用随机访问功能(使用 l.at(i))。

【问题讨论】:

  • l[4] = -1; 有什么问题或者 l.at(4) = -1,如果你愿意的话。

标签: c++ stl vector


【解决方案1】:

atoperator[] 都返回对索引元素的引用,因此您可以简单地使用:

l.at(4) = -1;

l[4] = -1;

【讨论】:

  • 而且你最好养成使用at的习惯,不太习惯,但边界检查是无价的。
  • @Matt:虽然越界错误往往是程序员的错误,而at 会抛出异常。也就是说assert会更好,而且我认为MSVC和gcc都检查了迭代器。
  • 我们不在我工作的地方使用assert。我们有一个应该是稳定的测试环境,这样客户就可以在不经常被中断的情况下对其进行测试,因此我们有一个类似的断言,它抛出而不是中止程序......因此atASSERT对我有同样的效果:)
  • @Milan:其实应该写成bounds-checking,也就是检查边界的行为。如果您有一个包含 5 个元素的向量 vec,则尝试访问索引 5 处的元素是错误的,有效索引为 0 到 4(包括),并且 5 及以上指向没有元素。 vec[5] 会……做点什么。可能会重新解释留下的任何字节,就好像它们是有效对象一样,或者可能更糟。这是未定义的行为,所以任何事情都可能发生,真的。 vec.at(5) 但是会首先在访问元素之前检查边界,并在这种情况下抛出。
  • @MatthieuM。现在明白你的意思了。因此,我创建了一个向量:std::vector&lt;int&gt; vec = {10, 20, 30, 40, 50};,并在我的 gcc 中多次运行std::cout &lt;&lt; vec[5];,并且每次都显示0。另一方面,当我尝试运行std::cout &lt;&lt; vec.at(5); 时,我得到terminate called after throwing an instance of 'std::out_of_range' what(): vector::_M_range_check: __n (which is 5) &gt;= this-&gt;size() (which is 5) Aborted (core dumped) 错误。我以前不知道这种行为。所以,非常感谢你指出这一点:)
【解决方案2】:

应该这样做:

l[4] = -1

【讨论】:

    【解决方案3】:

    您可以使用subscript operator

    l[4] = -1
    

    【讨论】:

    • 嗨,Tom,您能告诉我们如何为 2D 向量实现这一点,例如“vector> VC”或“vector VC (100,100)”。
    【解决方案4】:

    即使@JamesMcNellis 的回答是有效的,我还是想解释一下关于错误处理的一些事情,以及还有另一种方法可以做你想做的事情。

    您有四种方法可以访问向量中的特定项目:

    • 使用[] 运算符
    • 使用成员函数at(...)
    • 结合使用迭代器和给定的偏移量
    • 使用标准 C++ 库的 algorithm 标头中的 std::for_each。这是我可以推荐的另一种方式(它在内部使用迭代器)。您可以阅读更多相关信息,例如 here

    在以下示例中,我将使用以下向量作为实验鼠并解释前三种方法:

    static const int arr[] = {1, 2, 3, 4};
    std::vector<int> v(arr, arr+sizeof(arr)/sizeof(arr[0]));
    

    这将创建一个向量,如下所示:

    1 2 3 4
    

    首先让我们看看[]的做事方式。它的工作方式与您在使用普通数组时所期望的方式几乎相同。您提供一个索引,然后可能访问您想要的项目。我说可能是因为[] 运算符不检查向量是否实际上有那么多项目。这会导致静默无效内存访问。示例:

    v[10] = 9;
    

    这可能会也可能不会导致即时崩溃。最坏的情况当然是如果它没有,并且您实际上得到了似乎是有效的值。与数组类似,这可能会导致浪费时间来尝试查找原因,例如 1000 行代码稍后您会得到 100 而不是 234 的值,这在某种程度上与您检索项目的那个位置有关来自你的矢量。

    更好的方法是使用at(...)。这将自动检查out of bounds 的行为并中断抛出std::out_of_range。所以在我们有的情况下

    v.at(10) = 9;
    

    我们会得到:

    在抛出 'std::out_of_range' 的实例后调用终止
    what(): vector::_M_range_check: __n (即 10) >= this->size() (即4)

    第三种方式类似于[] 运算符,因为您可以把事情搞砸。向量就像数组一样,是一系列包含相同类型数据的连续内存块。这意味着您可以通过将起始地址分配给迭代器来使用起始地址,然后只需向该迭代器添加偏移量。偏移量仅代表您要遍历的第一项之后的项目数:

    std::vector<int>::iterator it = v.begin(); // First element of your vector
    *(it+0) = 9;  // offest = 0 basically means accessing v.begin()
    // Now we have 9 2 3 4 instead of 1 2 3 4
    *(it+1) = -1; // offset = 1 means first item of v plus an additional one
    // Now we have 9 -1 3 4 instead of 9 2 3 4
    // ...
    

    如您所见,我们也可以这样做

    *(it+10) = 9;
    

    这又是一次无效的内存访问。这与使用at(0 + offset) 基本相同,但没有越界错误检查。

    我建议尽可能使用at(...),不仅因为它与迭代器访问相比更具可读性,而且因为我在上面提到的带有偏移组合的迭代器和[] 运算符都对无效索引进行了错误检查.

    【讨论】:

      【解决方案5】:

      我更喜欢

      l.at(4)= -1;
      

      而 [4] 是您的索引

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-11
        • 2016-10-11
        • 1970-01-01
        • 2011-02-07
        • 2019-04-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多