【问题标题】:How to properly push back and then loop through vector of objects located in the heap?如何正确推回然后循环遍历位于堆中的对象向量?
【发布时间】:2020-05-18 21:14:11
【问题描述】:

我有以下课程:

#include <iostream>
#include <math.h>
#include <vector>
class minimal
{
private:
    int x;
    int y;
public:
    minimal(int x = NAN, int y = NAN)  // default constructor
    {
        this->x = x;
        this->y = y;
    }
    ~minimal(){}
    void setvals(int xin, int yin)
    {
        this->x = xin;
        this->y = yin;
    }
    int getx() {return this->x;}
};
int main() {
    // goal: create a vector of type minimal to be located in the heap
    std::vector<minimal*> vectinheap;

    minimal * min_ptr = new minimal;
    for (int i = 0; i < 4; ++i)
    {
        min_ptr->setvals(i, -i);
        vectinheap.push_back(min_ptr);  // send a local copy to vectinheap?
    }
    delete min_ptr;  // free the heap
    min_ptr = nullptr;  // free dangling pointer
    // now how to iterate through vect in heap.. ?
    return 0;
}

由此引发了几个问题:

  1. 当我说vectinheap.push_back(min_ptr) 时,是要使向量中的每个值最终都指向同一个实例,还是会像我想要的那样附加当前实例?
  2. 加载位于堆中的向量后,如何通过索引向量来遍历和访问每个实例?

【问题讨论】:

  • 您能否将显示的代码缩减为minimal reproducible example?我的印象是不需要所有的课程细节。你能用简单的整数代替这个问题吗?例如。在main() 内将所有minimal 替换为整数,将min_ptr-&gt;setvals(xlocal, ylocal); 替换为*min_ptr = i;。我想你会意识到你的问题的答案。
  • 你知道让多个指针指向同一个对象和创建新对象的区别吗?
  • @Yunnosch 我不知道如何在不完全回答我的问题的情况下使它变得更小。它都位于main.cpp 我应该休息一下吗?我的目标不是让多个指针指向同一个对象(参见问题 1)。
  • 首先在向量中存储minimal*而不是minimal有什么意义?
  • @AlexanderHuszagh 是的,感谢您的洞察力。非常有帮助。这是个好地方。

标签: c++ object vector heap-memory


【解决方案1】:
  1. 您最好将std::vector&lt;minimal*&gt; vectinheap; 重命名为vect_of_ptr,因为您的向量不在堆中。
  2. 当我说 vectinheap.push_back(min_ptr) 是要让每个 向量中的值最终指向同一个实例,或者 它会像我想要的那样附加当前实例吗?

您正在将指向在堆上分配的同一 minimalobject 的指针推送到向量 vectinheap

  1. 加载位于堆中的向量后,我该如何迭代 通过索引向量来访问每个实例?

你这样做:

for(const auto& item: vectinheap)
{
    //item is a pointer, you can get your object by dereference it using *
}

注意:你只在堆中创建了一个minimal 的对象,但是你将四个指向它的指针(同一个对象) 压入你的向量中。你已经删除了delete min_ptr; 的对象。并且循环遍历向量并取消引用其中的指针将变为undefined

您应该通过将 minimal * min_ptr = new minimal; 移动到您的 for 循环中来修复它。当您循环访问 vectinheap 时,不要忘记删除它们

【讨论】:

  • 向量数据,除非使用自定义分配器,否则总是在“堆”中,无论是否使用指针作为value_type。无论哪种方式,数据都将存储在“堆”中。
  • @AlexanderHuszagh 然而向量本身从来都不是,OP 声明它的方式。我认为这是 szppeter 的观点。
  • 向量本身可能不在堆中,但向量中的数据始终在。值得注意的是,因为我 99% 确定这是 OP 的问题。
【解决方案2】:

我假设您有 C# 或 Java 背景? (因此尝试更新一切的原因?)。您在 C++ 中执行此操作的方式如下:

int main() {
    // store a vector of minimal structs
    std::vector<minimal> vectinheap;

    int n = 4;
    for (int i = 0; i < n; ++i)
    {
        int xlocal = i;  // set dummy vals for filling vectinheap
        int ylocal = -i;

        // emplace_back will construct a new item at the end of the vector
        vectinheap.emplace_back(xlocal, ylocal);
    }


    // and now to iterate (range based for loop - best method)
    for(auto& value : vectinheap)
    {
      std::cout << value.getx() << ' ' <<  value.gety() << std::endl;
    }

    // the less good way using iterators
    for(auto it = vectinheap.begin(); it != vectinheap.end(); ++it)
    {
      std::cout << it->getx() << ' ' <<  it->gety() << std::endl;
    }

    // and using indices if you really must
    for(size_t i = 0; i < vectinheap.size(); ++i)
    {
      std::cout << vectinheap[i].getx() << ' ' <<  vectinheap[i].gety() << std::endl;
    }

}

但是,使用 push_back/emplace_back 构造一个简单的 POD 数组是一种非常低效的方法。通常最好预先分配一次,然后简单地填充数据。这样您就不会经常问“我可以在这个数组中追加一个项目而不调整它的大小吗?”每次循环迭代。

    int n = 4;

    // allocate enough memory for 'n' structs
    std::vector<minimal> vectinheap(n);

    for (int i = 0; i < n; ++i)
    {
        int xlocal = i;  // set dummy vals for filling vectinheap
        int ylocal = -i;

        // just use the array brackets to access
        vectinheap[i].setvals(xlocal, ylocal);
    }

【讨论】:

    猜你喜欢
    • 2014-02-22
    • 2012-01-22
    • 2012-09-12
    • 2022-10-13
    • 2019-09-10
    • 2016-08-09
    • 1970-01-01
    • 1970-01-01
    • 2020-06-09
    相关资源
    最近更新 更多