堆栈内存中对象的向量

Vector of objects in stack memory

本文关键字:向量 对象 内存 堆栈      更新时间:2023-10-16

我想创建一个对象向量,但我不想在堆上分配它们。我想把它们分配到堆栈内存中。但是我遇到了一些问题。

struct Object { int x; Object(int x) { this->x = x; } };
int main() {
    std::vector<Object*> v;
    for (int i = 0; i < 5; i++) {
        Object o (i);
        v.push_back(&o);
        std::cout << &o << std::endl; // keeps printing the same mem address...
                                      // ...implying that these are all the same object
    }
}

我怀疑对象在每次for循环迭代后超出作用域后删除了自己。

现在,我知道你可以在每次迭代中只做v.push_back(new Object(i)),这是可行的。但是,我不希望将这些对象分配到需要手动管理内存的堆上。

你基本上是正确的,"对象在超出作用域后[被销毁]"。打印的内容也会让人困惑。根据编译器在循环内分配具有"自动存储持续时间"的变量的方式,堆栈变量Object o总是具有相同的地址。

std::vector<Object*> v;
for (int i = 0; i < 5; i++) {
    Object o (i);
    v.push_back(&o);
    // Variable o still exists on the stack
    std::cout << &o << std::endl; // Prints the address of the automatic variable 'o'
}
// At this point, no objects exist; they all went out of scope
// every pointer in v is invalid, pointing to the "ghost" of a destoryed object.

我认为你正在寻找的更简单的方法是简单地创建一个对象向量。

std::vector<Object> v;
for (int i = 0; i < 5; i++) {
    v.push_back(Object(i));
    std::cout << &(v.back()) << std::endl; // Prints the address of the Object just added
}

也就是说,你应该明白std::vector<Object>将适当地管理你的对象生命周期,当向量本身超出作用域时销毁对象。但是对象实际上是存储在自由存储区中。

下面是ideone在编译和运行object向量时的输出:

0x8e66008
0x8e6601c
0x8e66030
0x8e66034
0x8e66050

如果你真的不想在堆栈上分配它们,而只是想管理内存,你真的应该花几个小时来填补一些知识空白。

特别是,掌握大量关于RAII的知识对于有效地使用c++和c++ 11是至关重要的。我强烈推荐《c++语言参考》第4版。第四版很重要,因为它与第三版非常不同。

在其中,它将向您展示可能想要使用std::vector<std::unique_ptr>来解决这个特定问题,或者使Object本身成为一个托管对象(实现移动语义)。

删除的是向量,而不是对象。

下面的操作意味着将指针保存在向量v中:

std::vector<Object*> v;

你可以这样做:

std::vector<Object> v;

在这种情况下,你得到许多对象,但然后你得到你的对象的副本,有时要么是不可能的,要么不是你想要的东西(虽然新版本的c++编译器可以做一个移动而不是复制,但我不认为这会在这种情况下工作…)

如果你想分配对象然后自动删除,另一种方法是使用智能指针。

#include <memory>
std::vector<std::shared_ptr<Object> > v;

在这种情况下,对象由您分配,并在删除vector时释放。

然而,你的问题是你在堆栈上初始化对象,并将堆栈指针赋值给vector。我想象一下,你的打印显示你的指针总是相同的。这意味着之前的对象被销毁,并在每次迭代时创建一个新对象。

所以我将替换这些行:

std::vector<Object*> v;
    Object o (i);
    v.push_back(&o);

std::vector<std::shared_ptr<Object> > v;
    std::shared<Object> o(new Object(i));
    v.push_back(o);

如果你对共享指针一无所知,我建议你仔细研究一下。这在使用new分配对象时非常有用。此外,还有一些所谓的循环引用的陷阱(例如,检查weak_ptr)。但是通过这种方式,你不需要管理内存,并且你有好的指针。

如果你更喜欢对象本身的解决方案,它将是这样的:

std::vector<Object> v;
    Object o(i);
    v.push_back(o);

这样可以避免堆,但是,每次push_back(或移动)时都会生成副本。所以如果你的对象很大,那就不是个好主意了。

同样,在你的对象中,如果你最终使用指针,使用智能指针也会对你有很大的帮助。这是了解它们的好方法