内部地址空间重用与在循环内创建的向量

时间:2011-01-28 14:32:58

标签: c++ arrays memory loops vector

下面的设计示例显示了循环内部的重复地址。当我在MinGW GCC 4.5.0上进行优化和不进行优化时,都会出现相同的现象。我看到的问题是,当我在循环内部创建向量时,内部数组有时会占用与上一次迭代中创建的向量相同的内存地址。我的问题是,是什么原因造成的?

这个问题与我有关,因为我有一些代码(基本上)将对循环内创建的向量的引用传递给新线程。线程互相践踏并导致程序崩溃。当我更改代码以在循环之外创建向量时,程序运行正常并产生与我的程序的单线程版本相同的结果。

#include <iostream>
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <cstdlib>
//using NULL;
#include <algorithm>
using std::for_each;
#include <tr1/functional>
using std::tr1::bind;
using std::tr1::placeholders::_1;

template<typename T>
void write_address(T const & arg){
    cout<<" "<<&arg;
}

template <typename T>
void write_container_addresses(vector<T> const & container){
    for_each(container.begin(),container.end(),
            write_address<T>);
    cout<<endl;
}

template <typename T>
void write_container_container_addresses(
        vector<vector<T> > const & container){
    for_each(container.begin(),container.end(),
            write_container_addresses<T>);
}

int main() {
    vector<vector<int> > stacked_vector(5);
    for_each(stacked_vector.begin(),stacked_vector.end(),
            bind(&vector<int>::reserve,_1,9));
    for_each(stacked_vector.begin(),stacked_vector.end(),
            bind(&vector<int>::resize,_1,5,0));

    cout<<"stacked vector addresses"<<endl;
    for (size_t i = 0;i<stacked_vector.size();i++){
        write_container_addresses<int>(stacked_vector[i]);
    }
    cout<<endl;

    cout<<"another print of stacked vector addresses"<<endl;
    write_container_container_addresses(stacked_vector);
    cout<<endl;

    vector<vector<int> > other_stacked_vector;

    cout<<"other vector addresses"<<endl;
    for (size_t i = 0;i<stacked_vector.size();i++){
        other_stacked_vector.push_back(vector<int>());
        other_stacked_vector.back().reserve(9);
        other_stacked_vector.back().resize(5,0);
        write_container_addresses<int>(other_stacked_vector[i]);
    }
    cout<<endl;

    cout<<"another write of other vector addresses"<<endl;
    write_container_container_addresses<int>(other_stacked_vector);

    return 0;
}

输出:

C:\workspace\test_of_pointer_vector_addresses\Debug>test_of_pointer_vector_addre
sses.exe
stacked vector addresses
 0x3e3e08 0x3e3e0c 0x3e3e10 0x3e3e14 0x3e3e18
 0x3e3e38 0x3e3e3c 0x3e3e40 0x3e3e44 0x3e3e48
 0x3e3e68 0x3e3e6c 0x3e3e70 0x3e3e74 0x3e3e78
 0x3e3e98 0x3e3e9c 0x3e3ea0 0x3e3ea4 0x3e3ea8
 0x3e3ec8 0x3e3ecc 0x3e3ed0 0x3e3ed4 0x3e3ed8

another print of stacked vector addresses
 0x3e3e08 0x3e3e0c 0x3e3e10 0x3e3e14 0x3e3e18
 0x3e3e38 0x3e3e3c 0x3e3e40 0x3e3e44 0x3e3e48
 0x3e3e68 0x3e3e6c 0x3e3e70 0x3e3e74 0x3e3e78
 0x3e3e98 0x3e3e9c 0x3e3ea0 0x3e3ea4 0x3e3ea8
 0x3e3ec8 0x3e3ecc 0x3e3ed0 0x3e3ed4 0x3e3ed8

other vector addresses
 0x3e3f10 0x3e3f14 0x3e3f18 0x3e3f1c 0x3e3f20
 0x3e3f10 0x3e3f14 0x3e3f18 0x3e3f1c 0x3e3f20
 0x3e3f10 0x3e3f14 0x3e3f18 0x3e3f1c 0x3e3f20
 0x3e2430 0x3e2434 0x3e2438 0x3e243c 0x3e2440
 0x3e2430 0x3e2434 0x3e2438 0x3e243c 0x3e2440

another write of other vector addresses
 0x3e3f40 0x3e3f44 0x3e3f48 0x3e3f4c 0x3e3f50
 0x3e3f60 0x3e3f64 0x3e3f68 0x3e3f6c 0x3e3f70
 0x3e24c8 0x3e24cc 0x3e24d0 0x3e24d4 0x3e24d8
 0x3e24e8 0x3e24ec 0x3e24f0 0x3e24f4 0x3e24f8
 0x3e2430 0x3e2434 0x3e2438 0x3e243c 0x3e2440

1 个答案:

答案 0 :(得分:3)

我看到的问题是在这个循环中:

cout<<"other vector addresses"<<endl;
for (size_t i = 0;i<stacked_vector.size();i++){
    other_stacked_vector.push_back(vector<int>());
    other_stacked_vector.back().reserve(9);
    other_stacked_vector.back().resize(5,0);
    write_container_addresses<int>(other_stacked_vector[i]);
}
cout<<endl;

在将每个子矢量添加到堆叠矢量后,您正在写入地址。问题是在下一次迭代和push_back()调用时,为前一次迭代显示的地址可能不再有效。这是因为push_back操作可能必须重新分配内存,导致向量堆栈中的所有向量都被移动。

更简单的演示是:

vector<int> vec;
vec.push_back(1);
int* p = &vec[0];
vec.push_back(2);
cout << *p << endl;  //ERROR: p possibly no longer valid.

在向量中没有保留空间的push_back调用之后,向量中内部存储器的所有指针/引用/迭代器都可能无效,因为它可能必须重新分配并移动内存以添加新项目并保持连续存储。

我想在你的多线程情况下发生的事情是你将一个子向量的引用传递给一个线程,然后你将其他子向量添加到原始线程中的堆叠向量,这可能使第二个线程中对子向量的引用无效。