将对象的地址添加到循环中的向量中

时间:2016-04-20 00:55:03

标签: c++ loops pointers

我需要创建几个对象并将它们放在一个列表中(我正在使用std :: vector)。此外,我需要列表项指向对象的地址,以便我对对象所做的更改也反映在列表中。 但问题是,列表中的每个项目都指向循环中创建的最后一个对象。

    for(int i=0;i<50;i++){
        for(int j=0;j<50;j++){
            Grass g1;
            g1.position.x = i;
            g1.position.y = j;
            grassList.push_back(&g1);
        }
    }

列表中草对象的属性应为..

[0,0]
[0,1]
[0,2]
.
.
.
.
[49,49]

但它出现了......

[49,49]
[49,49]
[49,49]
[49,49]
.
.
.
[49,49]

3 个答案:

答案 0 :(得分:3)

您正在将指向局部变量的指针推送到向量。局部变量在其范围的末尾被销毁(在这种情况下,倒数第二个})。因此,在} 未定义行为之后取消引用任何指针。您看到的输出是未定义行为的完全有效结果。

在这里使用指针是没有意义的。仅在绝对必要时才使用它们(包括new)。有关详细信息,请参阅Why should I use a pointer rather than the object itself?

这是正确的方法:

std::vector<Grass> grassList;
         // ^^^^^ not pointers!

for(int i=0; i<50; ++i) {
    for(int j=0; j<50; ++j) {
        Grass g1;
        g1.position.x = i;
        g1.position.y = j;
        grassList.push_back(g1);
    }
}

答案 1 :(得分:2)

如果您习惯使用其他使用变量计数的语言,那么您可能已经预料到了

Grass g1;

正在创造一个新的&#34; Grass&#34;对象循环的每次迭代。不是,C ++不是一种重新计算的语言。

相反,它会在堆栈上创建范围的局部变量。

因为您在循环中执行此操作,所以每次都可能在内存中的相同位置。

您需要:

  1. 只需将容器作为Grass对象的容器,而不是指针:让容器为您处理分配。

  2. 使用C ++ 11的unique_ptr和C ++ 14&#39; make_unique为循环的每次迭代动态创建Grass的实例。当包含unique_ptrs的向量超出范围时,它们将自动释放。

  3. 使用newdelete关键字手动分配和释放Grass对象以指向。

  4. 选项1:

    #include <vector>
    
    struct Grass {
        struct {
            int x, y;
        } position;
    };
    
    int main() {
        std::vector<Grass> grassList;
        for(int i=0;i<50;i++){
            for(int j=0;j<50;j++){
                Grass g1;
                g1.position.x = i;
                g1.position.y = j;
                grassList.push_back(g1);
            }
        }  
    }
    

    现场演示:http://ideone.com/DQs3VA

    选项2:

    #include <memory>
    #include <vector>
    
    struct Grass {
        struct {
            int x, y;
        } position;
    };
    
    int main() {
        std::vector<std::unique_ptr<Grass>> grassList;
        for(int i=0;i<50;i++){
            for(int j=0;j<50;j++){
                auto g1 = std::make_unique<Grass>();
                g1->position.x = i;
                g1->position.y = j;
                grassList.push_back(std::move(g1));
            }
        }   
    }
    

    现场演示:http://ideone.com/hJUdwR

    选项3:

    #include <vector>
    
    struct Grass {
        struct {
            int x, y;
        } position;
    };
    
    int main() {
        std::vector<Grass*> grassList;
        for(int i=0;i<50;i++){
            for(int j=0;j<50;j++){
                Grass* g1 = new Grass;
                g1->position.x = i;
                g1->position.y = j;
                grassList.push_back(g1);
            }
        }
        // ...
        for (auto& g1: grassList) {
            delete g1;
        }
        grassList.clear();
    }
    

    现场演示:http://ideone.com/GTk7ON

答案 2 :(得分:0)

如果出于任何(未指明的)原因需要将指针存储到对象的位置,则需要这个

std::vector<Grass*> grassList;  // Assumed you already have something like this
for(int i=0;i<50;i++){
    for(int j=0;j<50;j++){
        Grass* gp1 = new Grass;
        gp1->position.x = i;
        gp1->position.y = j;
        grassList.push_back(gp1);
    }
}

这可以避免破坏您存储的指针所指向的对象。例如,见Creating an object: with or without `new` 您必须使用delete来适当删除对象以释放内存。

但是根据你的需要,你也可以使用一组对象而不是一个指针数组,如tuple_cat所示。