std::copy_n 不改变目标矢量大小

std::copy_n doesn't change destination vector size

如果我为向量保留一些 space,然后用 std::copy_n() 复制其中的一些值,我得到正确复制并可访问的值,但向量的大小仍然零。这是预期的行为吗?我是否应该调整向量的大小,即使它没有那么有效?

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

int main()
{
    std::vector<double> src, dest;

    for(double x = 0.0; x < 100.0; ++x)
        src.push_back(x);

    dest.reserve(src.size());

    std::copy_n(src.cbegin(), src.size(), dest.begin());

    std::cout << "src.size() = " << src.size() << std::endl;
    std::cout << "dest.size() = " << dest.size() << std::endl;

    for(size_t i = 0; i < src.size(); ++i)
        std::cout << dest[i] << "  ";

}

测试的编译器:clang、gcc、Visual C++

but the size of the vector is still zero

std::copy_n 不会改变容器的大小,只是复制值并步进迭代器;它甚至没有关于容器的任何信息。所以代码有未定义的行为,即使它看起来工作正常。

Should I resize the vector instead, even if it is not as efficient?

是的,您可以使用 std::vector::resize 而不是 std::vector::reserve 来解决问题。正如你所想的,这意味着所有元素将首先由 resize 构造,然后由 copy_n.

赋值。

您可以使用 std::back_inserter,它会通过调用容器的 push_back() 成员函数(即直接构造元素)在容器的末尾追加元素,从而增加容器的大小。例如

dest.reserve(src.size());
std::copy_n(src.cbegin(), src.size(), std::back_inserter(dest));

一个std::vector有一个尺寸和一个容量。它保留了比必要的多一些 space 以使插入速度更快。 reserve 使您能够指定该容量,而 resize 更改矢量的实际大小。

你的dest在你调用reserve后分配了内存来存储元素,但它没有调用构造函数,它实际上是空的,所以你的代码导致了UB。使用resize实际创建那些元素然后就可以了。

dest.resize(src.size());
std::copy_n(src.cbegin(), src.size(), dest.begin());

std::cout << "src.size() = " << src.size() << std::endl;
std::cout << "dest.size() = " << dest.size() << std::endl;

for(size_t i = 0; i < src.size(); ++i)
    std::cout << dest[i] << "  ";

关于标准库算法,要记住的关键是它们在 范围 上运行,而不是容器。容器是您可以创建范围的方式之一,但它们不是唯一的方式。将结果写入范围的算法假定它们正在写入有效位置;他们不会,也不能扩展他们写入的范围。

因此,当您调用 std::copy_n 时,您必须提供一个足以容纳结果的范围。这意味着使用 dest.resize(src.size()); 设置范围,而不仅仅是使用 dest.reserve(std.size());.

分配内存

或者,您可以通过使用 std::back_inserter(dest) 而不是 dest.begin().

调用算法来提供一个知道它附加到容器并需要调整大小的范围