'std::vector' 的迭代器构造函数是否复制数据?

Does `std::vector`'s iterator constructor copy the data?

提问人:rocksNwaves 提问时间:6/30/2023 最后编辑:rocksNwaves 更新时间:6/30/2023 访问量:94

问:

在函数调用中,我有一个动态分配的数组,我想用它来填充向量。这里的上下文是,我知道我无法返回指针,因为它在返回后超出了范围。

我的问题是关于在构造向量后调用创建的指针的安全性。向量是拥有指针的所有权,并因此负责销毁,还是只是复制它的数据?我担心的是,如果我调用并且向量的基础数组与原始数组是相同的内存,那么我将提前销毁其内容。freefree

__host__ 
std::vector<float> mult(std::vector<float> x, float scalar) {

    int n = x.size();

    int n_threads = 256;
    int n_blocks = (int)ceil(n / n_threads);
    size_t bytes = n * sizeof(float);    

    float *d_x; // gpu "device" inputs
    float *d_y; // gpu "device" outputs
    float *h_y; // cpu "host" outputs
    
    h_y = (float *)malloc(n * sizeof(float));
    cudaMalloc(&d_x, bytes);
    cudaMalloc(&d_y, bytes);

    cudaMemcpy(d_x, x.data(), bytes, cudaMemcpyHostToDevice);
    mult<<<n_blocks, n_threads>>>(n, d_x, scalar, d_y);
    cudaMemcpy(h_y, d_y, bytes, cudaMemcpyDeviceToHost);

    cudaFree(d_x);
    cudaFree(d_y);

    std::vector<float> y(h_y, h_y + sizeof(h_y));

    free(h_y); <<<< CALL IN QUESTION
    return y;
}

文档说:

(3)range构造函数构造一个包含与以下元素一样多的容器 范围 [first,last),每个元素从其 该范围内的相应元素,顺序相同。

我在谷歌上搜索了“emplace constructed”,但没有找到这个术语的定义,但我觉得这是我问题的关键。

C++ 指针 malloc

评论

1赞 NathanOliver 6/30/2023
vector管理自己的内存,这就是推荐它的原因。 将缓冲区复制到 Vecotr 中。std::vector<float> y(h_y, h_y + sizeof(h_y));
2赞 NathanOliver 6/30/2023
它们不能指向内存中的同一位置,因为 vector 管理它自己的内存。当您创建一个内存时,它会分配自己的内存并对其进行处理。
2赞 n. m. could be an AI 6/30/2023
为什么需要这个指针和 ?向量本身完全能够提供数据的缓冲区。即 当然是完全错误的。mallocfreecudaMemcpystd::vector<float> y(n); cudaMemcpy(y.data(), d_y, bytes, cudaMemcpyDeviceToHost);h_y + sizeof(h_y)
1赞 François Andrieux 6/30/2023
h_y是指向数组的指针,而不是数组。 是指针的大小,与要复制的范围的大小无关。您需要添加实际的元素数才能获得“结束”指针(大概)。sizeof(h_y)h_yn
1赞 François Andrieux 6/30/2023
@rocksNwaves 通常C++术语“管理自己的内存”意味着“[如果需要]分配自己的内存”。无论是否需要内存分配,都可以假设标准容器将在需要时自行管理内存。您似乎在问的是,是否取决于提供给它的范围的持续有效性。标准 C++ 容器使用值语义。他们复制给定的范围。初始化向量后,无需维护原始初始化数据。std::vector

答:

0赞 Martin York 6/30/2023 #1

有趣的是:

    // Step 1: Allocate memory.
    float *h_y; // cpu "host" outputs
    h_y = (float *)malloc(n * sizeof(float));


    // Step 2: Copy data from source into allocated memory
    cudaMemcpy(h_y, d_y, bytes, cudaMemcpyDeviceToHost);

    // Step 3: Copy data from allocated memory to vector
    //         With a bug.
    std::vector<float> y(h_y, h_y + sizeof(h_y));

    // Step 4: Free Allocated memory.
    free(h_y);

您的初始问题?“Step 4: free(h_y)”是否弄乱了向量内存。

简短的回答:不。
长答案:容器(如 vector)管理自己的内存。因此,它会分配空间并将数据复制到此内存中。所以你应该释放这个内存。

但是:你有一个错误:

std::vector<float> y(h_y, h_y + sizeof(h_y));
// sizeof(h_y) is the size of the pointer (probably 8 bytes)
// Not the size of the allocated memory.
// So you have only copyied one or two floats into the vector.

您可能想要:

std::vector<float> y(h_y, h_y + n);

Emplace 构造:

这只是一种奇特的说法,我们将避免调用默认构造函数,然后调用复制构造函数。相反,它将通过调用构造函数传递对范围中每个项的引用来确保向量中的对象是“就地”构造的。

由于您没有实际的构造函数,因此只需将范围中的每个值直接复制到分配的向量内存中即可。float

你应该做什么:

不要分配临时缓冲区。只需确保向量具有足够的大小,然后直接从 CUDA 复制到您的向量中即可。

    // Step 1: Allocate memory (in the vector)
    std::vector<float> y(n);

    // Step 2: Copy data from source into allocated memory
    cudaMemcpy(&y[0], d_y, bytes, cudaMemcpyDeviceToHost);

    // Note: &y[0] is the address of the first element in the vector.
    //             vectors are contiguous.