6

我知道当函数完成执行时,分配在该函数堆栈上的变量变得不可访问。但是,向量类型在堆上分配它们的元素,不管它们是如何分配的。例如,

vector<int> A;

将在堆而不是堆栈上为其元素分配空间。

我的问题是,假设我有以下代码:

int main(int argc, char *argv[]) {
    // initialize a vector
    vector<int> A = initVector(100000);

    // do something with the vector...

    return 0;
}


// initialize the vector
vector<int> initVector(int size) {
    vector<int> A (size);  // initialize the vector "on the stack"

    // fill the vector with a sequence of numbers...
    int counter = 0;
    for (vector<int>::iterator i = A.begin(); i != A.end(); i++) {
        (*i) = counter++;
    }

    return A;
}

在 main 函数中使用向量 A 时会出现内存访问问题吗?我尝试了几次,它们都正常工作,但我担心这可能只是运气。

我看到的方式是,向量 A 在堆上分配其元素,但它在堆栈本身上分配了一些“开销”参数(可能是向量的大小)。因此,如果这些参数被另一个分配覆盖,在主函数中使用向量可能会导致内存访问问题。有任何想法吗?

4

3 回答 3

6

当您执行“返回 A”时;您按值返回,因此您获得了向量的副本——C++ 创建一个新实例并在其上调用复制构造函数或 operator=。因此,在这种情况下,分配内存的位置并不重要,因为无论如何您都必须复制它并销毁旧副本(尽管有一些可能的优化)。

向量(以及所有其他 STL 容器)中的数据也按值移动,因此您存储整数的副本,而不是指向它们的指针。这意味着您的对象可以在任何容器操作中多次复制,并且它们必须正确实现复制构造函数和/或赋值运算符。默认情况下,C++ 会为您生成这些(只需对所有成员变量调用 copy ctor),但它们并不总是做正确的事情。

如果您想在 STL 容器中存储指针,请考虑使用共享指针包装器(std::shared_ptr 或 boost::shared_ptr)。他们将确保正确处理内存。

于 2012-04-06T18:24:53.697 回答
1

是的,它将正常工作,因为元素的内存已分配,这将用于构建vector<int> A =变量。但是,就性能而言,这不是最好的主意。

我建议将您的功能更改为以下内容

void initVector(vector<int>& a, int size) 

有关用法的其他参考,请参阅Returning a STL vector from a function...</a> 和[C++] Returning Vector from Function

有关性能的其他参考(使用 C++11),请参阅正确方法(移动语义)从 C++0x 中的函数调用返回 std::vector

于 2012-04-06T18:08:12.553 回答
0

C++ 向量实际上有两块内存,它们用一个指针链接。第一个在堆栈中,第二个在堆中。因此,您在单个对象中同时具有堆栈和堆的功能。

std::vector<int> vec;
vec.push_back(10);
vec.push_back(20);
vec.push_back(30);
std::cout << sizeof(vec) << std::endl;

运行该代码后,您会注意到堆栈区域不包含元素,但它仍然存在。因此,当您将向量从函数传递到另一个函数时,您需要操作堆栈区域,并且向量将像任何其他基于堆栈的对象一样被复制。

于 2012-04-06T18:33:47.067 回答