繁体   English   中英

向量的 std::copy 无法正常工作

[英]std::copy for vector doesn't work properly

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

int main()
{
    vector<int> a{ 1, 2, 3 };
    copy(a.begin(), a.end(), back_inserter(a));
    for (const int& x : a)
        cout << x << ' ';
}

Output:

1 2 3 1 -572662307 -572662307

预期 output:

1 2 3 1 2 3

我不知道为什么会这样。 这种行为的原因是什么?

问题是随着向量的增长,您提供的迭代器可能会失效。 您可以使用reserve来解决这个问题。 一般来说,如果您提前知道大小,那么使用reserve是一个好主意,这样可以减少分配:

#include <algorithm>
#include <vector>

int main() {
  std::vector<int> a{1, 2, 3};
  a.reserve(a.size() * 2);

  a.insert(a.end(), a.begin(), a.end());
}

请注意, insert通常比back_inserter更好更简单。

通常,您的程序具有未定义的行为,因为在向向量添加新元素期间迭代器可能会变得无效。

您必须在向量中保留足够的 memory。 例如

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main() 
{
    std::vector<int> v = { 1, 2, 3 };

    v.reserve( 2 * v.size() );
    
    std::copy( std::begin( v ), std::end( v ), std::back_inserter( v ) );
    
    for ( const auto &item : v ) std::cout << item << ' ';
    std::cout << '\n';
    
    return 0;
}

如果您的编译器支持 C++ 17 标准(在 C++ 14 标准中,要求指定复制范围的迭代器不是向量本身的迭代器),那么您可以使用方法 insert,例如

#include <iostream>
#include <vector>
#include <iterator>

int main() 
{
    std::vector<int> v = { 1, 2, 3 };

    v.insert( std::end( v ), std::begin( v ), std::end( v ) );

    for ( const auto &item : v ) std::cout << item << ' ';
    std::cout << '\n';
    
    return 0;
}

cppreference copy的可能实现:

 template<class InputIt, class OutputIt> OutputIt copy(InputIt first, InputIt last, OutputIt d_first) { while (first;= last) { *d_first++ = *first++; } return d_first; }

使用back_inserter *first++将在向量上调用push_back 当向量需要重新分配时,调用push_back可能会使所有迭代器失效。 因此,您的代码具有未定义的行为。

请注意, back_inserter有点异国情调。 它违反了迭代器和容器通常的严格分离,因为迭代器必须存储对容器的引用。 仅此一项并不能解释您看到的效果,但它表明当迭代器实际修改容器时需要小心。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM