push_back会不断将向量中的所有条目重写为push_back项吗?

时间:2017-12-06 21:14:27

标签: c++ pointers for-loop vector

我目前正在尝试制作vector的轻量级副本。副本意味着副本的内容是原始vector指针的vector。我出于某些原因这样做有问题...每次push_back复制vector的新条目时,我似乎都会覆盖vector中的所有条目我只是push_back,为什么会发生这种情况:

MWE:

// This file is a "Hello, world!" in C++ language by GCC for wandbox.
#include <iostream>
#include <cstdlib>
#include <experimental/filesystem>
#include <vector>
#include <algorithm>


struct abstract_data_structure
{
    int x;
    int y;
    std::vector<int> points;
    std::string name;

    abstract_data_structure(int x, int y , std::vector<int> points, std::string name)
    {
        this->x= x;
        this->y = y;
        this->points = points;
        this->name = name;
    }
};

int main()
{
     std::vector<abstract_data_structure> storage;
     std::vector<abstract_data_structure*> copy_of_storage;

     std::srand(std::time(0));
     for (int i = 0; i< 5 ; i++)
     {     
        int x = std::rand();
        int y = std::rand();
        std::vector<int> vecOfRandomNums(10);
        std::generate(vecOfRandomNums.begin(), vecOfRandomNums.end(), []() {
           return rand() % 100;
        });
        std::string name = "something"+std::to_string(i);
        abstract_data_structure something(x,y,vecOfRandomNums,name);
        storage.push_back(something);

     }

    std::cout << storage.size() << std::endl;
    std::cout << "Make the copy" << std::endl;

    for (auto element : storage)
    {
        std::cout << "in storage" << std::endl;
        std::cout << element.name << std::endl;
        copy_of_storage.push_back(&(element));
        std::cout << "in copy storage" << std::endl; 

        for (auto copy_element: copy_of_storage)
        {
            std::cout << copy_element->name << std::endl; 
        }
    }


}

https://wandbox.org/permlink/Xn96xbIshd6RXTRa

输出:

5
Make the copy
in storage
something0
in copy storage
something0
in storage
something1
in copy storage
something1
something1
in storage
something2
in copy storage
something2
something2
something2
in storage
something3
in copy storage
something3
something3
something3
something3
in storage
something4
in copy storage
something4
something4
something4
something4
something4
0

正如人们可能看到的那样,复制向量中的所有条目都被修改为指向插入的最后一个元素?为什么呢?

2 个答案:

答案 0 :(得分:1)

//***1***
for (auto element : storage)
{
    std::cout << "in storage" << std::endl;
    std::cout << element.name << std::endl;
    //***2***
    copy_of_storage.push_back(&(element));
    std::cout << "in copy storage" << std::endl; 

    for (auto copy_element: copy_of_storage)
    {
        std::cout << copy_element->name << std::endl; 
    }
}

***1***,您正在制作每个变量的本地副本。

***2***,您将获取该本地副本的地址并将其保存在矢量中。

当您离开范围时,该对象已被破坏且不再存在。因此,当您稍后尝试阅读它时,您会得到未定义的行为,这意味着您无法保证将要发生的行为。

似乎正在发生的事情是,每次,你取得局部变量的地址,以及for循环的每次迭代,变量的位置是相同的,因此最终复制向量中的每个地址都是相同的,并且因为最近的副本是您最近使用的storage向量中的任何一个条目,所以指针读取的是该版本

如果您将***1***更改为for(auto & element : storage),则应解决您的问题。

答案 1 :(得分:0)

问题比您可能怀疑的要深一些。在

std::vector<abstract_data_structure> storage;
std::vector<abstract_data_structure*> copy_of_storage;

copy_of_storage不能是storage的副本,不需要额外的努力,也可能是abstract_data_structure s的动态分配。

copy_of_storage包含指针,这些指针必须指向abstract_data_structure s。这些abstract_data_structure可能是也可能不是副本。

天真的修复,交换

for (auto element : storage)

代表

for (auto & element : storage)

使元素成为abstract_data_structure中存储的storage的引用。这意味着element引用的变量的寿命比for循环的单次迭代长,但是

copy_of_storage.push_back(&(element));

不会复制。它只指向abstract_data_structure内的原始storage。有时这很有用,但是当一个列表应该是另一个列表的副本时,它可能应该直接引用另一个列表。

例如,向abstract_data_structure添加另一个storage将使指针无效。 storage的内容可以在现有存储中移动。存储器可以用更大的块替换,指针指向无效的存储器。各种令人讨厌的事情都可能发生。

相反,我建议

std::vector<abstract_data_structure> storage;
std::vector<abstract_data_structure> copy_of_storage;

以后

for (auto & element : storage)

copy_of_storage.push_back(element);

现在你有一份副本。

但是......有更简单的方法。 std::vector是一只非常聪明的野兽。你可以

copy_of_storage = storage;

storage将自行复制。

推荐的额外阅读:What is The Rule of Three?这不是您的示例所必需的,但在编程生涯的早期学习非常重要。

相关问题